activity_notification 1.7.1 → 2.0.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 +5 -5
- data/.gitignore +3 -0
- data/.travis.yml +16 -2
- data/CHANGELOG.md +22 -2
- data/Gemfile +7 -0
- data/Procfile +2 -0
- data/README.md +366 -32
- data/Rakefile +19 -10
- data/activity_notification.gemspec +5 -3
- data/app/channels/activity_notification/notification_channel.rb +37 -0
- data/app/channels/activity_notification/notification_with_devise_channel.rb +51 -0
- data/app/controllers/activity_notification/notifications_controller.rb +1 -1
- data/app/controllers/activity_notification/subscriptions_controller.rb +1 -1
- data/app/jobs/activity_notification/notify_all_job.rb +16 -0
- data/app/jobs/activity_notification/notify_job.rb +17 -0
- data/app/jobs/activity_notification/notify_to_job.rb +16 -0
- data/app/views/activity_notification/notifications/default/_default_without_grouping.html.erb +1 -1
- data/app/views/activity_notification/notifications/default/index.html.erb +55 -2
- data/bin/_dynamodblocal +4 -0
- data/{scripts → bin}/bundle_update.sh +1 -0
- data/bin/deploy_on_heroku.sh +14 -0
- data/bin/install_dynamodblocal.sh +5 -0
- data/bin/start_dynamodblocal.sh +47 -0
- data/bin/stop_dynamodblocal.sh +34 -0
- data/gemfiles/Gemfile.rails-4.2 +1 -0
- data/gemfiles/Gemfile.rails-5.0 +2 -0
- data/gemfiles/Gemfile.rails-5.1 +1 -0
- data/gemfiles/Gemfile.rails-5.2 +1 -0
- data/gemfiles/Gemfile.rails-6.0.rc +21 -0
- data/lib/activity_notification.rb +1 -0
- data/lib/activity_notification/apis/notification_api.rb +289 -136
- data/lib/activity_notification/apis/subscription_api.rb +80 -53
- data/lib/activity_notification/common.rb +3 -3
- data/lib/activity_notification/config.rb +89 -33
- data/lib/activity_notification/controllers/common_controller.rb +19 -7
- data/lib/activity_notification/helpers/errors.rb +4 -0
- data/lib/activity_notification/helpers/view_helpers.rb +1 -1
- data/lib/activity_notification/models/concerns/notifiable.rb +61 -53
- data/lib/activity_notification/models/concerns/subscriber.rb +7 -6
- data/lib/activity_notification/models/concerns/target.rb +73 -28
- data/lib/activity_notification/optional_targets/base.rb +2 -2
- data/lib/activity_notification/orm/active_record/notification.rb +4 -23
- data/lib/activity_notification/orm/dynamoid.rb +495 -0
- data/lib/activity_notification/orm/dynamoid/extension.rb +184 -0
- data/lib/activity_notification/orm/dynamoid/notification.rb +189 -0
- data/lib/activity_notification/orm/dynamoid/subscription.rb +82 -0
- data/lib/activity_notification/orm/mongoid.rb +4 -1
- data/lib/activity_notification/orm/mongoid/notification.rb +8 -25
- data/lib/activity_notification/orm/mongoid/subscription.rb +1 -1
- data/lib/activity_notification/roles/acts_as_notifiable.rb +33 -5
- data/lib/activity_notification/roles/acts_as_target.rb +62 -9
- data/lib/activity_notification/version.rb +1 -1
- data/lib/generators/templates/activity_notification.rb +30 -7
- data/lib/tasks/activity_notification_tasks.rake +14 -4
- data/spec/channels/notification_channel_shared_examples.rb +59 -0
- data/spec/channels/notification_channel_spec.rb +50 -0
- data/spec/channels/notification_with_devise_channel_spec.rb +99 -0
- data/spec/concerns/apis/notification_api_spec.rb +2 -2
- data/spec/concerns/apis/subscription_api_spec.rb +2 -2
- data/spec/concerns/models/notifiable_spec.rb +72 -7
- data/spec/concerns/models/subscriber_spec.rb +53 -49
- data/spec/concerns/models/target_spec.rb +135 -13
- data/spec/config_spec.rb +41 -1
- data/spec/controllers/notifications_controller_shared_examples.rb +7 -3
- data/spec/controllers/subscriptions_controller_shared_examples.rb +7 -3
- data/spec/helpers/view_helpers_spec.rb +12 -10
- data/spec/models/dummy/dummy_group_spec.rb +4 -0
- data/spec/models/dummy/dummy_notifiable_spec.rb +4 -0
- data/spec/models/dummy/dummy_notifier_spec.rb +4 -0
- data/spec/models/dummy/dummy_subscriber_spec.rb +3 -0
- data/spec/models/dummy/dummy_target_spec.rb +4 -0
- data/spec/models/notification_spec.rb +164 -45
- data/spec/models/subscription_spec.rb +69 -14
- data/spec/orm/dynamoid_spec.rb +115 -0
- data/spec/rails_app/app/assets/javascripts/application.js +2 -1
- data/spec/rails_app/app/assets/javascripts/cable.js +12 -0
- data/spec/rails_app/app/controllers/comments_controller.rb +3 -4
- data/spec/rails_app/app/models/admin.rb +6 -4
- data/spec/rails_app/app/models/article.rb +2 -2
- data/spec/rails_app/app/models/comment.rb +17 -5
- data/spec/rails_app/app/models/user.rb +5 -3
- data/spec/rails_app/app/views/activity_notification/notifications/users/overridden/custom/_test.html.erb +1 -0
- data/spec/rails_app/config/application.rb +6 -1
- data/spec/rails_app/config/cable.yml +8 -0
- data/spec/rails_app/config/dynamoid.rb +5 -0
- data/spec/rails_app/config/environment.rb +4 -1
- data/spec/rails_app/config/environments/production.rb +1 -1
- data/spec/rails_app/config/initializers/activity_notification.rb +30 -7
- data/spec/rails_app/config/locales/activity_notification.en.yml +2 -0
- data/spec/rails_app/db/seeds.rb +21 -5
- data/spec/rails_app/lib/mailer_previews/mailer_preview.rb +12 -4
- data/spec/roles/acts_as_notifiable_spec.rb +2 -2
- data/spec/roles/acts_as_target_spec.rb +1 -1
- data/spec/spec_helper.rb +15 -8
- metadata +67 -20
- data/spec/rails_app/app/models/.keep +0 -0
- data/spec/rails_app/app/views/activity_notification/notifications/users/overriden/custom/_test.html.erb +0 -1
|
@@ -52,7 +52,8 @@ module ActivityNotification
|
|
|
52
52
|
if subscription_params[:subscribing] == false && subscription_params[:subscribing_to_email].nil?
|
|
53
53
|
subscription_params[:subscribing_to_email] = subscription_params[:subscribing]
|
|
54
54
|
end
|
|
55
|
-
subscription =
|
|
55
|
+
subscription = Subscription.new(subscription_params)
|
|
56
|
+
subscription.assign_attributes(target: self)
|
|
56
57
|
subscription.subscribing? ?
|
|
57
58
|
subscription.assign_attributes(subscribing: true, subscribed_at: created_at) :
|
|
58
59
|
subscription.assign_attributes(subscribing: false, unsubscribed_at: created_at)
|
|
@@ -65,11 +66,11 @@ module ActivityNotification
|
|
|
65
66
|
optional_targets = subscription.subscribing_to_optional_target?(optional_target_name) ?
|
|
66
67
|
optional_targets.merge(
|
|
67
68
|
Subscription.to_optional_target_key(optional_target_name) => true,
|
|
68
|
-
Subscription.to_optional_target_subscribed_at_key(optional_target_name) => created_at
|
|
69
|
+
Subscription.to_optional_target_subscribed_at_key(optional_target_name) => Subscription.convert_time_as_hash(created_at)
|
|
69
70
|
) :
|
|
70
71
|
optional_targets.merge(
|
|
71
72
|
Subscription.to_optional_target_key(optional_target_name) => false,
|
|
72
|
-
Subscription.to_optional_target_unsubscribed_at_key(optional_target_name) => created_at
|
|
73
|
+
Subscription.to_optional_target_unsubscribed_at_key(optional_target_name) => Subscription.convert_time_as_hash(created_at)
|
|
73
74
|
)
|
|
74
75
|
end
|
|
75
76
|
subscription.assign_attributes(optional_targets: optional_targets)
|
|
@@ -128,7 +129,7 @@ module ActivityNotification
|
|
|
128
129
|
protected
|
|
129
130
|
|
|
130
131
|
# Returns if the target subscribes to the notification.
|
|
131
|
-
# This method can be
|
|
132
|
+
# This method can be overridden.
|
|
132
133
|
# @api protected
|
|
133
134
|
#
|
|
134
135
|
# @param [String] key Key of the notification
|
|
@@ -139,7 +140,7 @@ module ActivityNotification
|
|
|
139
140
|
end
|
|
140
141
|
|
|
141
142
|
# Returns if the target subscribes to the notification email.
|
|
142
|
-
# This method can be
|
|
143
|
+
# This method can be overridden.
|
|
143
144
|
# @api protected
|
|
144
145
|
#
|
|
145
146
|
# @param [String] key Key of the notification
|
|
@@ -151,7 +152,7 @@ module ActivityNotification
|
|
|
151
152
|
alias_method :_subscribes_to_email?, :_subscribes_to_notification_email?
|
|
152
153
|
|
|
153
154
|
# Returns if the target subscribes to the specified optional target.
|
|
154
|
-
# This method can be
|
|
155
|
+
# This method can be overridden.
|
|
155
156
|
# @api protected
|
|
156
157
|
#
|
|
157
158
|
# @param [String] key Key of the notification
|
|
@@ -19,6 +19,8 @@ module ActivityNotification
|
|
|
19
19
|
:_notification_email_allowed,
|
|
20
20
|
:_batch_notification_email_allowed,
|
|
21
21
|
:_notification_subscription_allowed,
|
|
22
|
+
:_notification_action_cable_allowed,
|
|
23
|
+
:_notification_action_cable_with_devise,
|
|
22
24
|
:_notification_devise_resource,
|
|
23
25
|
:_notification_current_devise_target,
|
|
24
26
|
:_printable_notification_target_name
|
|
@@ -35,13 +37,15 @@ module ActivityNotification
|
|
|
35
37
|
# Sets default values to target class fields.
|
|
36
38
|
# @return [NilClass] nil
|
|
37
39
|
def set_target_class_defaults
|
|
38
|
-
self._notification_email
|
|
39
|
-
self._notification_email_allowed
|
|
40
|
-
self._batch_notification_email_allowed
|
|
41
|
-
self._notification_subscription_allowed
|
|
42
|
-
self.
|
|
43
|
-
self.
|
|
44
|
-
self.
|
|
40
|
+
self._notification_email = nil
|
|
41
|
+
self._notification_email_allowed = ActivityNotification.config.email_enabled
|
|
42
|
+
self._batch_notification_email_allowed = ActivityNotification.config.email_enabled
|
|
43
|
+
self._notification_subscription_allowed = ActivityNotification.config.subscription_enabled
|
|
44
|
+
self._notification_action_cable_allowed = ActivityNotification.config.action_cable_enabled
|
|
45
|
+
self._notification_action_cable_with_devise = ActivityNotification.config.action_cable_with_devise
|
|
46
|
+
self._notification_devise_resource = ->(model) { model }
|
|
47
|
+
self._notification_current_devise_target = ->(current_resource) { current_resource }
|
|
48
|
+
self._printable_notification_target_name = :printable_name
|
|
45
49
|
nil
|
|
46
50
|
end
|
|
47
51
|
|
|
@@ -75,8 +79,8 @@ module ActivityNotification
|
|
|
75
79
|
end
|
|
76
80
|
target_notifications = target_notifications.limit(options[:limit]) if options[:limit].present?
|
|
77
81
|
as_latest_group_member ?
|
|
78
|
-
target_notifications.map{ |n| n.latest_group_member } :
|
|
79
|
-
target_notifications.to_a
|
|
82
|
+
target_notifications.latest_order!(reverse).map{ |n| n.latest_group_member } :
|
|
83
|
+
target_notifications.latest_order!(reverse).to_a
|
|
80
84
|
end
|
|
81
85
|
|
|
82
86
|
# Gets all notifications for this target type grouped by targets.
|
|
@@ -133,7 +137,7 @@ module ActivityNotification
|
|
|
133
137
|
end
|
|
134
138
|
|
|
135
139
|
# Resolves current authenticated target by devise authentication from current resource signed in with Devise.
|
|
136
|
-
# This method is able to be
|
|
140
|
+
# This method is able to be overridden.
|
|
137
141
|
#
|
|
138
142
|
# @param [Object] current_resource Current resource signed in with Devise
|
|
139
143
|
# @return [Object] Current authenticated target by devise authentication
|
|
@@ -150,15 +154,15 @@ module ActivityNotification
|
|
|
150
154
|
end
|
|
151
155
|
|
|
152
156
|
# Returns target email address for email notification.
|
|
153
|
-
# This method is able to be
|
|
157
|
+
# This method is able to be overridden.
|
|
154
158
|
#
|
|
155
159
|
# @return [String] Target email address
|
|
156
160
|
def mailer_to
|
|
157
161
|
resolve_value(_notification_email)
|
|
158
162
|
end
|
|
159
163
|
|
|
160
|
-
# Returns if sending notification email is allowed for the target from configured field or
|
|
161
|
-
# This method is able to be
|
|
164
|
+
# Returns if sending notification email is allowed for the target from configured field or overridden method.
|
|
165
|
+
# This method is able to be overridden.
|
|
162
166
|
#
|
|
163
167
|
# @param [Object] notifiable Notifiable instance of the notification
|
|
164
168
|
# @param [String] key Key of the notification
|
|
@@ -167,8 +171,8 @@ module ActivityNotification
|
|
|
167
171
|
resolve_value(_notification_email_allowed, notifiable, key)
|
|
168
172
|
end
|
|
169
173
|
|
|
170
|
-
# Returns if sending batch notification email is allowed for the target from configured field or
|
|
171
|
-
# This method is able to be
|
|
174
|
+
# Returns if sending batch notification email is allowed for the target from configured field or overridden method.
|
|
175
|
+
# This method is able to be overridden.
|
|
172
176
|
#
|
|
173
177
|
# @param [String] key Key of the notifications
|
|
174
178
|
# @return [Boolean] If sending batch notification email is allowed for the target
|
|
@@ -176,8 +180,8 @@ module ActivityNotification
|
|
|
176
180
|
resolve_value(_batch_notification_email_allowed, key)
|
|
177
181
|
end
|
|
178
182
|
|
|
179
|
-
# Returns if subscription management is allowed for the target from configured field or
|
|
180
|
-
# This method is able to be
|
|
183
|
+
# Returns if subscription management is allowed for the target from configured field or overridden method.
|
|
184
|
+
# This method is able to be overridden.
|
|
181
185
|
#
|
|
182
186
|
# @param [String] key Key of the notifications
|
|
183
187
|
# @return [Boolean] If subscription management is allowed for the target
|
|
@@ -186,13 +190,54 @@ module ActivityNotification
|
|
|
186
190
|
end
|
|
187
191
|
alias_method :notification_subscription_allowed?, :subscription_allowed?
|
|
188
192
|
|
|
193
|
+
# Returns if publishing WebSocket using ActionCable is allowed for the target from configured field or overridden method.
|
|
194
|
+
# This method is able to be overridden.
|
|
195
|
+
#
|
|
196
|
+
# @param [Object] notifiable Notifiable instance of the notification
|
|
197
|
+
# @param [String] key Key of the notification
|
|
198
|
+
# @return [Boolean] If publishing WebSocket using ActionCable is allowed for the target
|
|
199
|
+
def notification_action_cable_allowed?(notifiable = nil, key = nil)
|
|
200
|
+
resolve_value(_notification_action_cable_allowed, notifiable, key)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Returns if publishing WebSocket using ActionCable is allowed only for the authenticated target with Devise from configured field or overridden method.
|
|
204
|
+
#
|
|
205
|
+
# @return [Boolean] If publishing WebSocket using ActionCable is allowed for the target
|
|
206
|
+
def notification_action_cable_with_devise?
|
|
207
|
+
resolve_value(_notification_action_cable_with_devise)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# :only-rails5-plus#only-rails-with-callback-issue:
|
|
211
|
+
# :only-rails5-plus#only-rails-without-callback-issue:
|
|
212
|
+
# :only-rails5-plus#only-rails-with-callback-issue#except-dynamoid:
|
|
213
|
+
# :only-rails5-plus#only-rails-without-callback-issue#except-dynamoid:
|
|
214
|
+
if Rails::VERSION::MAJOR >= 5
|
|
215
|
+
# Returns notification ActionCable channel class name from action_cable_with_devise? configuration.
|
|
216
|
+
#
|
|
217
|
+
# @return [String] Notification ActionCable channel class name from action_cable_with_devise? configuration
|
|
218
|
+
def notification_action_cable_channel_class_name
|
|
219
|
+
notification_action_cable_with_devise? ? "ActivityNotification::NotificationWithDeviseChannel" : "ActivityNotification::NotificationChannel"
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
# :only-rails5-plus#only-rails-with-callback-issue:
|
|
223
|
+
# :only-rails5-plus#only-rails-without-callback-issue:
|
|
224
|
+
# :only-rails5-plus#only-rails-with-callback-issue#except-dynamoid:
|
|
225
|
+
# :only-rails5-plus#only-rails-without-callback-issue#except-dynamoid:
|
|
226
|
+
|
|
227
|
+
# Returns Devise resource model associated with this target.
|
|
228
|
+
#
|
|
229
|
+
# @return [Object] Devise resource model associated with this target
|
|
230
|
+
def notification_devise_resource
|
|
231
|
+
resolve_value(_notification_devise_resource)
|
|
232
|
+
end
|
|
233
|
+
|
|
189
234
|
# Returns if current resource signed in with Devise is authenticated for the notification.
|
|
190
|
-
# This method is able to be
|
|
235
|
+
# This method is able to be overridden.
|
|
191
236
|
#
|
|
192
237
|
# @param [Object] current_resource Current resource signed in with Devise
|
|
193
238
|
# @return [Boolean] If current resource signed in with Devise is authenticated for the notification
|
|
194
239
|
def authenticated_with_devise?(current_resource)
|
|
195
|
-
devise_resource =
|
|
240
|
+
devise_resource = notification_devise_resource
|
|
196
241
|
unless current_resource.blank? or current_resource.is_a? devise_resource.class
|
|
197
242
|
raise TypeError,
|
|
198
243
|
"Different type of current resource #{current_resource.class} "\
|
|
@@ -237,7 +282,7 @@ module ActivityNotification
|
|
|
237
282
|
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
|
238
283
|
# @return [Boolean] If the target has unopened notifications
|
|
239
284
|
def has_unopened_notifications?(options = {})
|
|
240
|
-
_unopened_notification_index(options).
|
|
285
|
+
_unopened_notification_index(options).exists?
|
|
241
286
|
end
|
|
242
287
|
|
|
243
288
|
# Returns automatically arranged notification index of the target.
|
|
@@ -415,7 +460,7 @@ module ActivityNotification
|
|
|
415
460
|
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
|
416
461
|
# @return [Array<Notificaion>] Unopened notification index of the target with attributes
|
|
417
462
|
def unopened_notification_index_with_attributes(options = {})
|
|
418
|
-
include_attributes
|
|
463
|
+
include_attributes(_unopened_notification_index(options)).to_a
|
|
419
464
|
end
|
|
420
465
|
|
|
421
466
|
# Gets opened notification index of the target with including attributes like target, notifiable, group and notifier.
|
|
@@ -436,7 +481,7 @@ module ActivityNotification
|
|
|
436
481
|
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
|
437
482
|
# @return [Array<Notificaion>] Opened notification index of the target with attributes
|
|
438
483
|
def opened_notification_index_with_attributes(options = {})
|
|
439
|
-
include_attributes
|
|
484
|
+
include_attributes(_opened_notification_index(options)).to_a
|
|
440
485
|
end
|
|
441
486
|
|
|
442
487
|
# Sends notification email to the target.
|
|
@@ -513,7 +558,7 @@ module ActivityNotification
|
|
|
513
558
|
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
|
514
559
|
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
|
515
560
|
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
|
516
|
-
# @return [ActiveRecord_AssociationRelation<Notificaion
|
|
561
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>|Mongoid::Criteria<Notificaion>|Dynamoid::Criteria::Chain] Unopened notification index of the target
|
|
517
562
|
def _unopened_notification_index(options = {})
|
|
518
563
|
reverse = options[:reverse] || false
|
|
519
564
|
with_group_members = options[:with_group_members] || false
|
|
@@ -533,7 +578,7 @@ module ActivityNotification
|
|
|
533
578
|
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
|
534
579
|
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
|
535
580
|
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
|
536
|
-
# @return [
|
|
581
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>|Mongoid::Criteria<Notificaion>|Dynamoid::Criteria::Chain] Opened notification index of the target
|
|
537
582
|
def _opened_notification_index(options = {})
|
|
538
583
|
limit = options[:limit] || ActivityNotification.config.opened_index_limit
|
|
539
584
|
reverse = options[:reverse] || false
|
|
@@ -546,11 +591,11 @@ module ActivityNotification
|
|
|
546
591
|
# Otherwise, target, notifiable and or notifier will be include without group.
|
|
547
592
|
# @api private
|
|
548
593
|
#
|
|
549
|
-
# @param [ActiveRecord_AssociationRelation<Notificaion
|
|
550
|
-
# @return [ActiveRecord_AssociationRelation<Notificaion
|
|
594
|
+
# @param [ActiveRecord_AssociationRelation<Notificaion>|Mongoid::Criteria<Notificaion>|Dynamoid::Criteria::Chain] target_index Notification index
|
|
595
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>|Mongoid::Criteria<Notificaion>|Dynamoid::Criteria::Chain] Notification index with attributes
|
|
551
596
|
def include_attributes(target_index)
|
|
552
597
|
if target_index.present?
|
|
553
|
-
Notification.group_member_exists?(target_index) ?
|
|
598
|
+
Notification.group_member_exists?(target_index.to_a) ?
|
|
554
599
|
target_index.with_target.with_notifiable.with_group.with_notifier :
|
|
555
600
|
target_index.with_target.with_notifiable.with_notifier
|
|
556
601
|
else
|
|
@@ -606,7 +651,7 @@ module ActivityNotification
|
|
|
606
651
|
if has_unopened_notifications?(options)
|
|
607
652
|
# Return unopened notifications first
|
|
608
653
|
target_unopened_index = arrange_single_notification_index(loading_unopened_index_method, options)
|
|
609
|
-
# Total limit
|
|
654
|
+
# Total limit of notification index
|
|
610
655
|
total_limit = options[:limit] || ActivityNotification.config.opened_index_limit
|
|
611
656
|
# Additionaly, return opened notifications unless unopened index size overs the limit
|
|
612
657
|
if (opened_limit = total_limit - target_unopened_index.size) > 0
|
|
@@ -28,13 +28,13 @@ module ActivityNotification
|
|
|
28
28
|
self.class.name.demodulize.underscore.to_sym
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
# Initialize method to be
|
|
31
|
+
# Initialize method to be overridden in user implementation class
|
|
32
32
|
# @param [Hash] _options Options for initializing
|
|
33
33
|
def initialize_target(_options = {})
|
|
34
34
|
raise NotImplementedError, "You have to implement #{self.class}##{__method__}"
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
# Publishing notification method to be
|
|
37
|
+
# Publishing notification method to be overridden in user implementation class
|
|
38
38
|
# @param [Notification] _notification Notification instance
|
|
39
39
|
# @param [Hash] _options Options for publishing
|
|
40
40
|
def notify(_notification, _options = {})
|
|
@@ -8,9 +8,7 @@ module ActivityNotification
|
|
|
8
8
|
include Common
|
|
9
9
|
include Renderable
|
|
10
10
|
include NotificationApi
|
|
11
|
-
|
|
12
|
-
self.table_name = ActivityNotification.config.table_name || ActivityNotification.config.notification_table_name
|
|
13
|
-
# self.table_name = ActivityNotification.config.notification_table_name
|
|
11
|
+
self.table_name = ActivityNotification.config.notification_table_name
|
|
14
12
|
|
|
15
13
|
# Belongs to target instance of this notification as polymorphic association.
|
|
16
14
|
# @scope instance
|
|
@@ -152,27 +150,10 @@ module ActivityNotification
|
|
|
152
150
|
# @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with notifier
|
|
153
151
|
scope :with_notifier, -> { includes(:notifier) }
|
|
154
152
|
|
|
155
|
-
# Returns latest notification instance.
|
|
156
|
-
# @return [Notification] Latest notification instance
|
|
157
|
-
def self.latest
|
|
158
|
-
latest_order.first
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
# Returns earliest notification instance.
|
|
162
|
-
# @return [Notification] Earliest notification instance
|
|
163
|
-
def self.earliest
|
|
164
|
-
earliest_order.first
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
# Selects unique keys from query for notifications.
|
|
168
|
-
# @return [Array<String>] Array of notification unique keys
|
|
169
|
-
def self.uniq_keys
|
|
170
|
-
# select method cannot be chained with order by other columns like created_at
|
|
171
|
-
# select(:key).distinct.pluck(:key)
|
|
172
|
-
pluck(:key).uniq
|
|
173
|
-
end
|
|
174
|
-
|
|
175
153
|
# Raise DeleteRestrictionError for notifications.
|
|
154
|
+
# @param [String] error_text Error text for raised exception
|
|
155
|
+
# @raise DeleteRestrictionError
|
|
156
|
+
# @return [void]
|
|
176
157
|
def self.raise_delete_restriction_error(error_text)
|
|
177
158
|
raise ::ActiveRecord::DeleteRestrictionError.new(error_text)
|
|
178
159
|
end
|
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
require 'dynamoid/adapter_plugin/aws_sdk_v3'
|
|
2
|
+
require_relative 'dynamoid/extension.rb'
|
|
3
|
+
|
|
4
|
+
module ActivityNotification
|
|
5
|
+
module Association
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
class_attribute :_associated_composite_records
|
|
10
|
+
self._associated_composite_records = []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class_methods do
|
|
14
|
+
# Defines has_many association with ActivityNotification models.
|
|
15
|
+
# @return [Dynamoid::Criteria::Chain] Database query of associated model instances
|
|
16
|
+
def has_many_records(name, options = {})
|
|
17
|
+
has_many_composite_xdb_records name, options
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Defines polymorphic belongs_to association using composite key with models in other database.
|
|
21
|
+
def belongs_to_composite_xdb_record(name, _options = {})
|
|
22
|
+
association_name = name.to_s.singularize.underscore
|
|
23
|
+
composite_field = "#{association_name}_key".to_sym
|
|
24
|
+
field composite_field, :string
|
|
25
|
+
associated_record_field = "#{association_name}_record".to_sym
|
|
26
|
+
field associated_record_field, :string if ActivityNotification.config.store_with_associated_records && _options[:store_with_associated_records]
|
|
27
|
+
|
|
28
|
+
self.instance_eval do
|
|
29
|
+
define_method(name) do |reload = false|
|
|
30
|
+
reload and self.instance_variable_set("@#{name}", nil)
|
|
31
|
+
if self.instance_variable_get("@#{name}").blank?
|
|
32
|
+
composite_key = self.send(composite_field)
|
|
33
|
+
if composite_key.present? && (class_name = composite_key.split(ActivityNotification.config.composite_key_delimiter).first).present?
|
|
34
|
+
object_class = class_name.classify.constantize
|
|
35
|
+
self.instance_variable_set("@#{name}", object_class.where(id: composite_key.split(ActivityNotification.config.composite_key_delimiter).last).first)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
self.instance_variable_get("@#{name}")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
define_method("#{name}=") do |new_instance|
|
|
42
|
+
if new_instance.nil?
|
|
43
|
+
self.send("#{composite_field}=", nil)
|
|
44
|
+
else
|
|
45
|
+
self.send("#{composite_field}=", "#{new_instance.class.name}#{ActivityNotification.config.composite_key_delimiter}#{new_instance.id}")
|
|
46
|
+
self.send("#{associated_record_field}=", new_instance.to_json) if ActivityNotification.config.store_with_associated_records && _options[:store_with_associated_records]
|
|
47
|
+
end
|
|
48
|
+
self.instance_variable_set("@#{name}", nil)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
define_method("#{association_name}_type") do
|
|
52
|
+
composite_key = self.send(composite_field)
|
|
53
|
+
composite_key.present? ? composite_key.split(ActivityNotification.config.composite_key_delimiter).first : nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
define_method("#{association_name}_id") do
|
|
57
|
+
composite_key = self.send(composite_field)
|
|
58
|
+
composite_key.present? ? composite_key.split(ActivityNotification.config.composite_key_delimiter).last : nil
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
self._associated_composite_records.push(association_name.to_sym)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Defines polymorphic has_many association using composite key with models in other database.
|
|
66
|
+
# @todo Add dependent option
|
|
67
|
+
def has_many_composite_xdb_records(name, options = {})
|
|
68
|
+
association_name = options[:as] || name.to_s.underscore
|
|
69
|
+
composite_field = "#{association_name}_key".to_sym
|
|
70
|
+
object_name = options[:class_name] || name.to_s.singularize.camelize
|
|
71
|
+
object_class = object_name.classify.constantize
|
|
72
|
+
|
|
73
|
+
self.instance_eval do
|
|
74
|
+
# Set default reload arg to true since Dynamoid::Criteria::Chain is stateful on the query
|
|
75
|
+
define_method(name) do |reload = true|
|
|
76
|
+
reload and self.instance_variable_set("@#{name}", nil)
|
|
77
|
+
if self.instance_variable_get("@#{name}").blank?
|
|
78
|
+
new_value = object_class.where(composite_field => "#{self.class.name}#{ActivityNotification.config.composite_key_delimiter}#{self.id}")
|
|
79
|
+
self.instance_variable_set("@#{name}", new_value)
|
|
80
|
+
end
|
|
81
|
+
self.instance_variable_get("@#{name}")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Defines update method as update_attributes method
|
|
88
|
+
def update(attributes)
|
|
89
|
+
attributes_with_association = attributes.map { |attribute, value|
|
|
90
|
+
self.class._associated_composite_records.include?(attribute) ?
|
|
91
|
+
["#{attribute}_key".to_sym, value.nil? ? nil : "#{value.class.name}#{ActivityNotification.config.composite_key_delimiter}#{value.id}"] :
|
|
92
|
+
[attribute, value]
|
|
93
|
+
}.to_h
|
|
94
|
+
update_attributes(attributes_with_association)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Monkey patching for Rails 6.0+
|
|
100
|
+
class ActiveModel::NullMutationTracker
|
|
101
|
+
# Monkey patching for Rails 6.0+
|
|
102
|
+
def force_change(attr_name); end if Rails::VERSION::MAJOR >= 6
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Entend Dynamoid to support ActivityNotification scope in Dynamoid::Criteria::Chain
|
|
106
|
+
# @private
|
|
107
|
+
module Dynamoid # :nodoc: all
|
|
108
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria.rb
|
|
109
|
+
# @private
|
|
110
|
+
module Criteria
|
|
111
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria/chain.rb
|
|
112
|
+
# @private
|
|
113
|
+
class Chain
|
|
114
|
+
# Selects all notification index.
|
|
115
|
+
# ActivityNotification::Notification.all_index!
|
|
116
|
+
# is defined same as
|
|
117
|
+
# ActivityNotification::Notification.group_owners_only.latest_order
|
|
118
|
+
# @scope class
|
|
119
|
+
# @example Get all notification index of the @user
|
|
120
|
+
# @notifications = @user.notifications.all_index!
|
|
121
|
+
# @notifications = @user.notifications.group_owners_only.latest_order
|
|
122
|
+
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
|
123
|
+
# @param [Boolean] with_group_members If notification index will include group members
|
|
124
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
125
|
+
def all_index!(reverse = false, with_group_members = false)
|
|
126
|
+
target_index = with_group_members ? self : group_owners_only
|
|
127
|
+
reverse ? target_index.earliest_order : target_index.latest_order
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Selects unopened notification index.
|
|
131
|
+
# ActivityNotification::Notification.unopened_index
|
|
132
|
+
# is defined same as
|
|
133
|
+
# ActivityNotification::Notification.unopened_only.group_owners_only.latest_order
|
|
134
|
+
# @scope class
|
|
135
|
+
# @example Get unopened notificaton index of the @user
|
|
136
|
+
# @notifications = @user.notifications.unopened_index
|
|
137
|
+
# @notifications = @user.notifications.unopened_only.group_owners_only.latest_order
|
|
138
|
+
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
|
139
|
+
# @param [Boolean] with_group_members If notification index will include group members
|
|
140
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
141
|
+
def unopened_index(reverse = false, with_group_members = false)
|
|
142
|
+
target_index = with_group_members ? unopened_only : unopened_only.group_owners_only
|
|
143
|
+
reverse ? target_index.earliest_order : target_index.latest_order
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Selects unopened notification index.
|
|
147
|
+
# ActivityNotification::Notification.opened_index(limit)
|
|
148
|
+
# is defined same as
|
|
149
|
+
# ActivityNotification::Notification.opened_only(limit).group_owners_only.latest_order
|
|
150
|
+
# @scope class
|
|
151
|
+
# @example Get unopened notificaton index of the @user with limit 10
|
|
152
|
+
# @notifications = @user.notifications.opened_index(10)
|
|
153
|
+
# @notifications = @user.notifications.opened_only(10).group_owners_only.latest_order
|
|
154
|
+
# @param [Integer] limit Limit to query for opened notifications
|
|
155
|
+
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
|
156
|
+
# @param [Boolean] with_group_members If notification index will include group members
|
|
157
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
158
|
+
def opened_index(limit, reverse = false, with_group_members = false)
|
|
159
|
+
target_index = with_group_members ? opened_only(limit) : opened_only(limit).group_owners_only
|
|
160
|
+
reverse ? target_index.earliest_order : target_index.latest_order
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Selects filtered notifications or subscriptions by associated instance.
|
|
164
|
+
# @scope class
|
|
165
|
+
# @param [String] name Association name
|
|
166
|
+
# @param [Object] instance Associated instance
|
|
167
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications or subscriptions
|
|
168
|
+
def filtered_by_association(name, instance)
|
|
169
|
+
instance.present? ? where("#{name}_key" => "#{instance.class.name}#{ActivityNotification.config.composite_key_delimiter}#{instance.id}") : where("#{name}_key.null" => true)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Selects filtered notifications or subscriptions by association type.
|
|
173
|
+
# @scope class
|
|
174
|
+
# @param [String] name Association name
|
|
175
|
+
# @param [Object] type Association type
|
|
176
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications or subscriptions
|
|
177
|
+
def filtered_by_association_type(name, type)
|
|
178
|
+
type.present? ? where("#{name}_key.begins_with" => "#{type}#{ActivityNotification.config.composite_key_delimiter}") : none
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Selects filtered notifications or subscriptions by association type and id.
|
|
182
|
+
# @scope class
|
|
183
|
+
# @param [String] name Association name
|
|
184
|
+
# @param [Object] type Association type
|
|
185
|
+
# @param [String] id Association id
|
|
186
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications or subscriptions
|
|
187
|
+
def filtered_by_association_type_and_id(name, type, id)
|
|
188
|
+
type.present? && id.present? ? where("#{name}_key" => "#{type}#{ActivityNotification.config.composite_key_delimiter}#{id}") : none
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Selects filtered notifications or subscriptions by target instance.
|
|
192
|
+
# ActivityNotification::Notification.filtered_by_target(@user)
|
|
193
|
+
# is the same as
|
|
194
|
+
# @user.notifications
|
|
195
|
+
# @scope class
|
|
196
|
+
# @param [Object] target Target instance for filter
|
|
197
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications or subscriptions
|
|
198
|
+
def filtered_by_target(target)
|
|
199
|
+
filtered_by_association("target", target)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Selects filtered notifications by notifiable instance.
|
|
203
|
+
# @example Get filtered unopened notificatons of the @user for @comment as notifiable
|
|
204
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_instance(@comment)
|
|
205
|
+
# @scope class
|
|
206
|
+
# @param [Object] notifiable Notifiable instance for filter
|
|
207
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
208
|
+
def filtered_by_instance(notifiable)
|
|
209
|
+
filtered_by_association("notifiable", notifiable)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Selects filtered notifications by group instance.
|
|
213
|
+
# @example Get filtered unopened notificatons of the @user for @article as group
|
|
214
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_group(@article)
|
|
215
|
+
# @scope class
|
|
216
|
+
# @param [Object] group Group instance for filter
|
|
217
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
218
|
+
def filtered_by_group(group)
|
|
219
|
+
filtered_by_association("group", group)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Selects filtered notifications or subscriptions by target_type.
|
|
223
|
+
# @example Get filtered unopened notificatons of User as target type
|
|
224
|
+
# @notifications = ActivityNotification.Notification.unopened_only.filtered_by_target_type('User')
|
|
225
|
+
# @scope class
|
|
226
|
+
# @param [String] target_type Target type for filter
|
|
227
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications or subscriptions
|
|
228
|
+
def filtered_by_target_type(target_type)
|
|
229
|
+
filtered_by_association_type("target", target_type)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Selects filtered notifications by notifiable_type.
|
|
233
|
+
# @example Get filtered unopened notificatons of the @user for Comment notifiable class
|
|
234
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_type('Comment')
|
|
235
|
+
# @scope class
|
|
236
|
+
# @param [String] notifiable_type Notifiable type for filter
|
|
237
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
238
|
+
def filtered_by_type(notifiable_type)
|
|
239
|
+
filtered_by_association_type("notifiable", notifiable_type)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Selects filtered notifications or subscriptions by key.
|
|
243
|
+
# @example Get filtered unopened notificatons of the @user with key 'comment.reply'
|
|
244
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_key('comment.reply')
|
|
245
|
+
# @scope class
|
|
246
|
+
# @param [String] key Key of the notification for filter
|
|
247
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications or subscriptions
|
|
248
|
+
def filtered_by_key(key)
|
|
249
|
+
where(key: key)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Selects filtered notifications or subscriptions by notifiable_type, group or key with filter options.
|
|
253
|
+
# @example Get filtered unopened notificatons of the @user for Comment notifiable class
|
|
254
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment' })
|
|
255
|
+
# @example Get filtered unopened notificatons of the @user for @article as group
|
|
256
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group: @article })
|
|
257
|
+
# @example Get filtered unopened notificatons of the @user for Article instance id=1 as group
|
|
258
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group_type: 'Article', filtered_by_group_id: '1' })
|
|
259
|
+
# @example Get filtered unopened notificatons of the @user with key 'comment.reply'
|
|
260
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_key: 'comment.reply' })
|
|
261
|
+
# @example Get filtered unopened notificatons of the @user for Comment notifiable class with key 'comment.reply'
|
|
262
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment', filtered_by_key: 'comment.reply' })
|
|
263
|
+
# @example Get custom filtered notificatons of the @user
|
|
264
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ custom_filter: ["created_at >= ?", time.hour.ago] })
|
|
265
|
+
# @scope class
|
|
266
|
+
# @param [Hash] options Options for filter
|
|
267
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
|
268
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
|
269
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
|
270
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
|
271
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
|
272
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ['created_at.gt': time.hour.ago])
|
|
273
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications or subscriptions
|
|
274
|
+
def filtered_by_options(options = {})
|
|
275
|
+
options = ActivityNotification.cast_to_indifferent_hash(options)
|
|
276
|
+
filtered_notifications = self
|
|
277
|
+
if options.has_key?(:filtered_by_type)
|
|
278
|
+
filtered_notifications = filtered_notifications.filtered_by_type(options[:filtered_by_type])
|
|
279
|
+
end
|
|
280
|
+
if options.has_key?(:filtered_by_group)
|
|
281
|
+
filtered_notifications = filtered_notifications.filtered_by_group(options[:filtered_by_group])
|
|
282
|
+
end
|
|
283
|
+
if options.has_key?(:filtered_by_group_type) && options.has_key?(:filtered_by_group_id)
|
|
284
|
+
filtered_notifications = filtered_notifications.filtered_by_association_type_and_id("group", options[:filtered_by_group_type], options[:filtered_by_group_id])
|
|
285
|
+
end
|
|
286
|
+
if options.has_key?(:filtered_by_key)
|
|
287
|
+
filtered_notifications = filtered_notifications.filtered_by_key(options[:filtered_by_key])
|
|
288
|
+
end
|
|
289
|
+
if options.has_key?(:custom_filter)
|
|
290
|
+
filtered_notifications = filtered_notifications.where(options[:custom_filter])
|
|
291
|
+
end
|
|
292
|
+
filtered_notifications
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Orders by latest (newest) first as created_at: :desc.
|
|
296
|
+
# It uses sort key of Global Secondary Index in DynamoDB tables.
|
|
297
|
+
# @return [Dynamoid::Criteria::Chain] Database query of notifications or subscriptions ordered by latest first
|
|
298
|
+
def latest_order
|
|
299
|
+
# order(created_at: :desc)
|
|
300
|
+
scan_index_forward(false)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Orders by earliest (older) first as created_at: :asc.
|
|
304
|
+
# It uses sort key of Global Secondary Index in DynamoDB tables.
|
|
305
|
+
# @return [Dynamoid::Criteria::Chain] Database query of notifications or subscriptions ordered by earliest first
|
|
306
|
+
def earliest_order
|
|
307
|
+
# order(created_at: :asc)
|
|
308
|
+
scan_index_forward(true)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# Orders by latest (newest) first as created_at: :desc and returns as array.
|
|
312
|
+
# @param [Boolean] reverse If notifications or subscriptions will be ordered as earliest first
|
|
313
|
+
# @return [Array] Array of notifications or subscriptions ordered by latest first
|
|
314
|
+
def latest_order!(reverse = false)
|
|
315
|
+
# order(created_at: :desc)
|
|
316
|
+
reverse ? earliest_order! : earliest_order!.reverse
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# Orders by earliest (older) first as created_at: :asc and returns as array.
|
|
320
|
+
# It does not use sort key in DynamoDB tables.
|
|
321
|
+
# @return [Array] Array of notifications or subscriptions ordered by earliest first
|
|
322
|
+
def earliest_order!
|
|
323
|
+
# order(created_at: :asc)
|
|
324
|
+
all.to_a.sort_by {|n| n.created_at }
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Orders by latest (newest) first as subscribed_at: :desc.
|
|
328
|
+
# @return [Array] Array of subscriptions ordered by latest subscribed_at first
|
|
329
|
+
def latest_subscribed_order
|
|
330
|
+
# order(subscribed_at: :desc)
|
|
331
|
+
earliest_subscribed_order.reverse
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Orders by earliest (older) first as subscribed_at: :asc.
|
|
335
|
+
# @return [Array] Array of subscriptions ordered by earliest subscribed_at first
|
|
336
|
+
def earliest_subscribed_order
|
|
337
|
+
# order(subscribed_at: :asc)
|
|
338
|
+
all.to_a.sort_by {|n| n.subscribed_at }
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Orders by key name as key: :asc.
|
|
342
|
+
# @return [Array] Array of subscriptions ordered by key name
|
|
343
|
+
def key_order
|
|
344
|
+
# order(key: :asc)
|
|
345
|
+
all.to_a.sort_by {|n| n.key }
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# Selects group owner notifications only.
|
|
349
|
+
# @scope class
|
|
350
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
351
|
+
def group_owners_only
|
|
352
|
+
where('group_owner_id.null': true)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# Selects group member notifications only.
|
|
356
|
+
# @scope class
|
|
357
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
358
|
+
def group_members_only
|
|
359
|
+
where('group_owner_id.not_null': true)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
# Selects unopened notifications only.
|
|
363
|
+
# @scope class
|
|
364
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
365
|
+
def unopened_only
|
|
366
|
+
where('opened_at.null': true)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# Selects opened notifications only without limit.
|
|
370
|
+
# Be careful to get too many records with this method.
|
|
371
|
+
# @scope class
|
|
372
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
373
|
+
def opened_only!
|
|
374
|
+
where('opened_at.not_null': true)
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Selects opened notifications only with limit.
|
|
378
|
+
# @scope class
|
|
379
|
+
# @param [Integer] limit Limit to query for opened notifications
|
|
380
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
381
|
+
def opened_only(limit)
|
|
382
|
+
limit == 0 ? none : opened_only!.limit(limit)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
# Selects group member notifications in unopened_index.
|
|
386
|
+
# @scope class
|
|
387
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
388
|
+
def unopened_index_group_members_only
|
|
389
|
+
group_owner_ids = unopened_index.map(&:id)
|
|
390
|
+
group_owner_ids.empty? ? none : where('group_owner_id.in': group_owner_ids)
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# Selects group member notifications in opened_index.
|
|
394
|
+
# @scope class
|
|
395
|
+
# @param [Integer] limit Limit to query for opened notifications
|
|
396
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
397
|
+
def opened_index_group_members_only(limit)
|
|
398
|
+
group_owner_ids = opened_index(limit).map(&:id)
|
|
399
|
+
group_owner_ids.empty? ? none : where('group_owner_id.in': group_owner_ids)
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# Selects notifications within expiration.
|
|
403
|
+
# @scope class
|
|
404
|
+
# @param [ActiveSupport::Duration] expiry_delay Expiry period of notifications
|
|
405
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
406
|
+
def within_expiration_only(expiry_delay)
|
|
407
|
+
where('created_at.gt': expiry_delay.ago)
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# Selects group member notifications with specified group owner ids.
|
|
411
|
+
# @scope class
|
|
412
|
+
# @param [Array<String>] owner_ids Array of group owner ids
|
|
413
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
|
414
|
+
def group_members_of_owner_ids_only(owner_ids)
|
|
415
|
+
owner_ids.present? ? where('group_owner_id.in': owner_ids) : none
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# Includes target instance with query for notifications or subscriptions.
|
|
419
|
+
# @return [Dynamoid::Criteria::Chain] Database query of notifications with target
|
|
420
|
+
def with_target
|
|
421
|
+
self
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# Includes notifiable instance with query for notifications.
|
|
425
|
+
# @return [Dynamoid::Criteria::Chain] Database query of notifications with notifiable
|
|
426
|
+
def with_notifiable
|
|
427
|
+
self
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# Includes group instance with query for notifications.
|
|
431
|
+
# @return [Dynamoid::Criteria::Chain] Database query of notifications with group
|
|
432
|
+
def with_group
|
|
433
|
+
self
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
# Includes group owner instances with query for notifications.
|
|
437
|
+
# @return [Dynamoid::Criteria::Chain] Database query of notifications with group owner
|
|
438
|
+
def with_group_owner
|
|
439
|
+
self
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
# Includes group member instances with query for notifications.
|
|
443
|
+
# @return [Dynamoid::Criteria::Chain] Database query of notifications with group members
|
|
444
|
+
def with_group_members
|
|
445
|
+
self
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
# Includes notifier instance with query for notifications.
|
|
449
|
+
# @return [Dynamoid::Criteria::Chain] Database query of notifications with notifier
|
|
450
|
+
def with_notifier
|
|
451
|
+
self
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# Dummy reload method for test of notifications or subscriptions.
|
|
455
|
+
def reload
|
|
456
|
+
self
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
# Returns latest notification instance.
|
|
460
|
+
# @return [Notification] Latest notification instance
|
|
461
|
+
def latest
|
|
462
|
+
latest_order.first
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
# Returns earliest notification instance.
|
|
466
|
+
# @return [Notification] Earliest notification instance
|
|
467
|
+
def earliest
|
|
468
|
+
earliest_order.first
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
# Returns latest notification instance.
|
|
472
|
+
# It does not use sort key in DynamoDB tables.
|
|
473
|
+
# @return [Notification] Latest notification instance
|
|
474
|
+
def latest!
|
|
475
|
+
latest_order!.first
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
# Returns earliest notification instance.
|
|
479
|
+
# It does not use sort key in DynamoDB tables.
|
|
480
|
+
# @return [Notification] Earliest notification instance
|
|
481
|
+
def earliest!
|
|
482
|
+
earliest_order!.first
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
# Selects unique keys from query for notifications or subscriptions.
|
|
486
|
+
# @return [Array<String>] Array of notification unique keys
|
|
487
|
+
def uniq_keys
|
|
488
|
+
all.to_a.collect {|n| n.key }.uniq
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
require_relative 'dynamoid/notification.rb'
|
|
495
|
+
require_relative 'dynamoid/subscription.rb'
|