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
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
require 'dynamoid/adapter_plugin/aws_sdk_v3'
|
|
2
|
+
|
|
3
|
+
# Entend Dynamoid to support none, limit, exists?, update_all in Dynamoid::Criteria::Chain.
|
|
4
|
+
# ActivityNotification project will try to contribute these fundamental functions to Dynamoid upstream.
|
|
5
|
+
# @private
|
|
6
|
+
module Dynamoid # :nodoc: all
|
|
7
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria.rb
|
|
8
|
+
# @private
|
|
9
|
+
module Criteria
|
|
10
|
+
# @private
|
|
11
|
+
class None < Chain
|
|
12
|
+
def ==(other)
|
|
13
|
+
other.is_a?(None)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def records
|
|
17
|
+
[]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def count
|
|
21
|
+
0
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def delete_all
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def empty?
|
|
28
|
+
true
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria/chain.rb
|
|
33
|
+
# @private
|
|
34
|
+
class Chain
|
|
35
|
+
def none
|
|
36
|
+
None.new(self.source)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Set query result limit as record_limit of Dynamoid
|
|
40
|
+
# @scope class
|
|
41
|
+
# @param [Integer] limit Query result limit as record_limit
|
|
42
|
+
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications or subscriptions
|
|
43
|
+
def limit(limit)
|
|
44
|
+
record_limit(limit)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Return if records exist
|
|
48
|
+
# @scope class
|
|
49
|
+
# @return [Boolean] If records exist
|
|
50
|
+
def exists?
|
|
51
|
+
record_limit(1).count > 0
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Return size of records as count
|
|
55
|
+
# @scope class
|
|
56
|
+
# @return [Integer] Size of records
|
|
57
|
+
def size
|
|
58
|
+
count
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
#TODO Make this batch
|
|
62
|
+
def update_all(conditions = {})
|
|
63
|
+
each do |document|
|
|
64
|
+
document.update_attributes(conditions)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria.rb
|
|
70
|
+
# @private
|
|
71
|
+
module ClassMethods
|
|
72
|
+
define_method(:none) do |*args, &blk|
|
|
73
|
+
chain = Dynamoid::Criteria::Chain.new(self)
|
|
74
|
+
chain.send(:none, *args, &blk)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Entend Dynamoid to support query and scan with 'null' and 'not_null' conditions
|
|
81
|
+
# @private
|
|
82
|
+
module Dynamoid # :nodoc: all
|
|
83
|
+
# @private
|
|
84
|
+
module Criteria
|
|
85
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria/chain.rb
|
|
86
|
+
# @private
|
|
87
|
+
module NullOperatorExtension
|
|
88
|
+
# @private
|
|
89
|
+
def field_hash(key)
|
|
90
|
+
name, operation = key.to_s.split('.')
|
|
91
|
+
val = type_cast_condition_parameter(name, query[key])
|
|
92
|
+
|
|
93
|
+
hash = case operation
|
|
94
|
+
when 'null'
|
|
95
|
+
{ null: val }
|
|
96
|
+
when 'not_null'
|
|
97
|
+
{ not_null: val }
|
|
98
|
+
else
|
|
99
|
+
return super(key)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
{ name.to_sym => hash }
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria/chain.rb
|
|
107
|
+
# @private
|
|
108
|
+
class Chain
|
|
109
|
+
prepend NullOperatorExtension
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# @private
|
|
114
|
+
module AdapterPlugin
|
|
115
|
+
# @private
|
|
116
|
+
class AwsSdkV3
|
|
117
|
+
|
|
118
|
+
NULL_OPERATOR_FIELD_MAP = {
|
|
119
|
+
null: 'NULL',
|
|
120
|
+
not_null: 'NOT_NULL'
|
|
121
|
+
}.freeze
|
|
122
|
+
|
|
123
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb
|
|
124
|
+
# @private
|
|
125
|
+
class Query < ::Dynamoid::AdapterPlugin::Query
|
|
126
|
+
# @private
|
|
127
|
+
def query_filter
|
|
128
|
+
conditions.except(*AwsSdkV3::RANGE_MAP.keys).reduce({}) do |result, (attr, cond)|
|
|
129
|
+
if AwsSdkV3::NULL_OPERATOR_FIELD_MAP.has_key?(cond.keys[0])
|
|
130
|
+
condition = { comparison_operator: AwsSdkV3::NULL_OPERATOR_FIELD_MAP[cond.keys[0]] }
|
|
131
|
+
else
|
|
132
|
+
condition = {
|
|
133
|
+
comparison_operator: AwsSdkV3::FIELD_MAP[cond.keys[0]],
|
|
134
|
+
attribute_value_list: AwsSdkV3.attribute_value_list(AwsSdkV3::FIELD_MAP[cond.keys[0]], cond.values[0].freeze)
|
|
135
|
+
}
|
|
136
|
+
end
|
|
137
|
+
result[attr] = condition
|
|
138
|
+
result
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb
|
|
144
|
+
# @private
|
|
145
|
+
class Scan < ::Dynamoid::AdapterPlugin::Scan
|
|
146
|
+
# @private
|
|
147
|
+
def scan_filter
|
|
148
|
+
conditions.reduce({}) do |result, (attr, cond)|
|
|
149
|
+
if AwsSdkV3::NULL_OPERATOR_FIELD_MAP.has_key?(cond.keys[0])
|
|
150
|
+
condition = { comparison_operator: AwsSdkV3::NULL_OPERATOR_FIELD_MAP[cond.keys[0]] }
|
|
151
|
+
else
|
|
152
|
+
condition = {
|
|
153
|
+
comparison_operator: AwsSdkV3::FIELD_MAP[cond.keys[0]],
|
|
154
|
+
attribute_value_list: AwsSdkV3.attribute_value_list(AwsSdkV3::FIELD_MAP[cond.keys[0]], cond.values[0].freeze)
|
|
155
|
+
}
|
|
156
|
+
end
|
|
157
|
+
result[attr] = condition
|
|
158
|
+
result
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
module ActivityNotification
|
|
167
|
+
# Dynamoid extension module for ActivityNotification.
|
|
168
|
+
module DynamoidExtension
|
|
169
|
+
extend ActiveSupport::Concern
|
|
170
|
+
|
|
171
|
+
class_methods do
|
|
172
|
+
# Defines delete_all method as calling delete_table and create_table methods
|
|
173
|
+
def delete_all
|
|
174
|
+
delete_table
|
|
175
|
+
create_table(sync: true)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Returns an instance of the specified +klass+ with the attributes of the current record.
|
|
180
|
+
def becomes(klass)
|
|
181
|
+
self
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
require 'dynamoid'
|
|
2
|
+
require 'activity_notification/apis/notification_api'
|
|
3
|
+
|
|
4
|
+
module ActivityNotification
|
|
5
|
+
module ORM
|
|
6
|
+
module Dynamoid
|
|
7
|
+
# Notification model implementation generated by ActivityNotification.
|
|
8
|
+
class Notification
|
|
9
|
+
include ::Dynamoid::Document
|
|
10
|
+
include ActiveModel::AttributeAssignment
|
|
11
|
+
include GlobalID::Identification
|
|
12
|
+
include DynamoidExtension
|
|
13
|
+
include Common
|
|
14
|
+
include Renderable
|
|
15
|
+
include Association
|
|
16
|
+
include NotificationApi
|
|
17
|
+
|
|
18
|
+
table name: ActivityNotification.config.notification_table_name, key: :id
|
|
19
|
+
|
|
20
|
+
# Belongs to target instance of this notification as polymorphic association using composite key.
|
|
21
|
+
# @scope instance
|
|
22
|
+
# @return [Object] Target instance of this notification
|
|
23
|
+
belongs_to_composite_xdb_record :target, store_with_associated_records: true
|
|
24
|
+
|
|
25
|
+
# Belongs to notifiable instance of this notification as polymorphic association using composite key.
|
|
26
|
+
# @scope instance
|
|
27
|
+
# @return [Object] Notifiable instance of this notification
|
|
28
|
+
belongs_to_composite_xdb_record :notifiable, store_with_associated_records: true
|
|
29
|
+
|
|
30
|
+
# Belongs to group instance of this notification as polymorphic association using composite key.
|
|
31
|
+
# @scope instance
|
|
32
|
+
# @return [Object] Group instance of this notification
|
|
33
|
+
belongs_to_composite_xdb_record :group
|
|
34
|
+
|
|
35
|
+
field :key, :string
|
|
36
|
+
field :parameters, :raw, default: {}
|
|
37
|
+
field :opened_at, :datetime
|
|
38
|
+
field :group_owner_id, :string
|
|
39
|
+
|
|
40
|
+
# Belongs to group owner notification instance of this notification.
|
|
41
|
+
# Only group member instance has :group_owner value.
|
|
42
|
+
# Group owner instance has nil as :group_owner association.
|
|
43
|
+
# @scope instance
|
|
44
|
+
# @return [Notification] Group owner notification instance of this notification
|
|
45
|
+
belongs_to :group_owner, { class_name: "ActivityNotification::Notification", foreign_key: :group_owner_id }.merge(Rails::VERSION::MAJOR >= 5 ? { optional: true } : {})
|
|
46
|
+
|
|
47
|
+
# Customized method that belongs to group owner notification instance of this notification.
|
|
48
|
+
# @raise [Errors::RecordNotFound] Record not found error
|
|
49
|
+
# @return [Notification] Group owner notification instance of this notification
|
|
50
|
+
def group_owner
|
|
51
|
+
group_owner_id.nil? ? nil : Notification.find(group_owner_id)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Has many group member notification instances of this notification.
|
|
55
|
+
# Only group owner instance has :group_members value.
|
|
56
|
+
# Group member instance has nil as :group_members association.
|
|
57
|
+
# @scope instance
|
|
58
|
+
# @return [Dynamoid::Criteria::Chain] Database query of the group member notification instances of this notification
|
|
59
|
+
# has_many :group_members, class_name: "ActivityNotification::Notification", foreign_key: :group_owner_id
|
|
60
|
+
def group_members
|
|
61
|
+
Notification.where(group_owner_id: id)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Belongs to :otifier instance of this notification.
|
|
65
|
+
# @scope instance
|
|
66
|
+
# @return [Object] Notifier instance of this notification
|
|
67
|
+
belongs_to_composite_xdb_record :notifier, store_with_associated_records: true
|
|
68
|
+
|
|
69
|
+
# Mandatory global secondary index to query effectively
|
|
70
|
+
global_secondary_index hash_key: :target_key, range_key: :created_at, projected_attributes: :all
|
|
71
|
+
global_secondary_index hash_key: :group_owner_id, range_key: :created_at, projected_attributes: :all
|
|
72
|
+
# Optional global secondary index to sort by created_at
|
|
73
|
+
global_secondary_index hash_key: :notifier_key, range_key: :created_at, projected_attributes: :all
|
|
74
|
+
global_secondary_index hash_key: :notifiable_key, range_key: :created_at, projected_attributes: :all
|
|
75
|
+
|
|
76
|
+
validates :target, presence: true
|
|
77
|
+
validates :notifiable, presence: true
|
|
78
|
+
validates :key, presence: true
|
|
79
|
+
|
|
80
|
+
%i[ all_index! unopened_index opened_index
|
|
81
|
+
filtered_by_association filtered_by_target filtered_by_instance filtered_by_group
|
|
82
|
+
filtered_by_target_type filtered_by_type filtered_by_key filtered_by_options
|
|
83
|
+
latest_order earliest_order latest_order! earliest_order!
|
|
84
|
+
group_owners_only group_members_only unopened_only opened_only! opened_only
|
|
85
|
+
unopened_index_group_members_only opened_index_group_members_only
|
|
86
|
+
within_expiration_only(expiry_delay
|
|
87
|
+
group_members_of_owner_ids_only
|
|
88
|
+
reload
|
|
89
|
+
latest earliest latest! earliest!
|
|
90
|
+
uniq_keys
|
|
91
|
+
].each do |method|
|
|
92
|
+
# Return a criteria chain in response to a method that will begin or end a chain.
|
|
93
|
+
# For more information, see Dynamoid::Criteria::Chain.
|
|
94
|
+
singleton_class.send(:define_method, method) do |*args, &block|
|
|
95
|
+
# Use scan_index_forward with true as default value to convert Dynamoid::Document into Dynamoid::Criteria::Chain
|
|
96
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/document.rb
|
|
97
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/components.rb
|
|
98
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria.rb
|
|
99
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria/chain.rb
|
|
100
|
+
scan_index_forward(true).send(method, *args, &block)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
%i[ with_target with_notifiable with_group with_group_owner with_group_members with_notifier ].each do |method|
|
|
105
|
+
singleton_class.send(:define_method, method) do |*args, &block|
|
|
106
|
+
self
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Returns if the notification is group owner.
|
|
111
|
+
# Calls NotificationApi#group_owner? as super method.
|
|
112
|
+
# @return [Boolean] If the notification is group owner
|
|
113
|
+
def group_owner?
|
|
114
|
+
super
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Raise ActivityNotification::DeleteRestrictionError for notifications.
|
|
118
|
+
# @param [String] error_text Error text for raised exception
|
|
119
|
+
# @raise ActivityNotification::DeleteRestrictionError
|
|
120
|
+
# @return [void]
|
|
121
|
+
def self.raise_delete_restriction_error(error_text)
|
|
122
|
+
raise ActivityNotification::DeleteRestrictionError, error_text
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Returns prepared notification object to store
|
|
126
|
+
# @return [Object] prepared notification object to store
|
|
127
|
+
# def prepare_to_store
|
|
128
|
+
# end
|
|
129
|
+
|
|
130
|
+
protected
|
|
131
|
+
|
|
132
|
+
# Returns count of group members of the unopened notification.
|
|
133
|
+
# This method is designed to cache group by query result to avoid N+1 call.
|
|
134
|
+
# @api protected
|
|
135
|
+
# @todo Avoid N+1 call
|
|
136
|
+
#
|
|
137
|
+
# @return [Integer] Count of group members of the unopened notification
|
|
138
|
+
def unopened_group_member_count
|
|
139
|
+
group_members.unopened_only.count
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Returns count of group members of the opened notification.
|
|
143
|
+
# This method is designed to cache group by query result to avoid N+1 call.
|
|
144
|
+
# @api protected
|
|
145
|
+
# @todo Avoid N+1 call
|
|
146
|
+
#
|
|
147
|
+
# @param [Integer] limit Limit to query for opened notifications
|
|
148
|
+
# @return [Integer] Count of group members of the opened notification
|
|
149
|
+
def opened_group_member_count(limit = ActivityNotification.config.opened_index_limit)
|
|
150
|
+
limit == 0 and return 0
|
|
151
|
+
group_members.opened_only(limit).to_a.length
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Returns count of group member notifiers of the unopened notification not including group owner notifier.
|
|
155
|
+
# This method is designed to cache group by query result to avoid N+1 call.
|
|
156
|
+
# @api protected
|
|
157
|
+
# @todo Avoid N+1 call
|
|
158
|
+
#
|
|
159
|
+
# @return [Integer] Count of group member notifiers of the unopened notification
|
|
160
|
+
def unopened_group_member_notifier_count
|
|
161
|
+
group_members.unopened_only
|
|
162
|
+
.filtered_by_association_type("notifier", notifier)
|
|
163
|
+
.where("notifier_key.ne": notifier_key)
|
|
164
|
+
.to_a
|
|
165
|
+
.collect {|n| n.notifier_key }.compact.uniq
|
|
166
|
+
.length
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Returns count of group member notifiers of the opened notification not including group owner notifier.
|
|
170
|
+
# This method is designed to cache group by query result to avoid N+1 call.
|
|
171
|
+
# @api protected
|
|
172
|
+
# @todo Avoid N+1 call
|
|
173
|
+
#
|
|
174
|
+
# @param [Integer] limit Limit to query for opened notifications
|
|
175
|
+
# @return [Integer] Count of group member notifiers of the opened notification
|
|
176
|
+
def opened_group_member_notifier_count(limit = ActivityNotification.config.opened_index_limit)
|
|
177
|
+
limit == 0 and return 0
|
|
178
|
+
group_members.opened_only(limit)
|
|
179
|
+
.filtered_by_association_type("notifier", notifier)
|
|
180
|
+
.where("notifier_key.ne": notifier_key)
|
|
181
|
+
.to_a
|
|
182
|
+
.collect {|n| n.notifier_key }.compact.uniq
|
|
183
|
+
.length
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'dynamoid'
|
|
2
|
+
require 'activity_notification/apis/subscription_api'
|
|
3
|
+
|
|
4
|
+
module ActivityNotification
|
|
5
|
+
module ORM
|
|
6
|
+
module Dynamoid
|
|
7
|
+
# Subscription model implementation generated by ActivityNotification.
|
|
8
|
+
class Subscription
|
|
9
|
+
include ::Dynamoid::Document
|
|
10
|
+
include ActiveModel::AttributeAssignment
|
|
11
|
+
include DynamoidExtension
|
|
12
|
+
include Association
|
|
13
|
+
include SubscriptionApi
|
|
14
|
+
|
|
15
|
+
table name: ActivityNotification.config.subscription_table_name, key: :id
|
|
16
|
+
|
|
17
|
+
# Belongs to target instance of this subscription as polymorphic association using composite key.
|
|
18
|
+
# @scope instance
|
|
19
|
+
# @return [Object] Target instance of this subscription
|
|
20
|
+
belongs_to_composite_xdb_record :target
|
|
21
|
+
|
|
22
|
+
field :key, :string
|
|
23
|
+
field :subscribing, :boolean, default: ActivityNotification.config.subscribe_as_default
|
|
24
|
+
field :subscribing_to_email, :boolean, default: ActivityNotification.config.subscribe_as_default
|
|
25
|
+
field :subscribed_at, :datetime
|
|
26
|
+
field :unsubscribed_at, :datetime
|
|
27
|
+
field :subscribed_to_email_at, :datetime
|
|
28
|
+
field :unsubscribed_to_email_at, :datetime
|
|
29
|
+
field :optional_targets, :raw, default: {}
|
|
30
|
+
|
|
31
|
+
global_secondary_index hash_key: :target_key, range_key: :created_at, projected_attributes: :all
|
|
32
|
+
|
|
33
|
+
validates :target, presence: true
|
|
34
|
+
validates :key, presence: true
|
|
35
|
+
validates_inclusion_of :subscribing, in: [true, false]
|
|
36
|
+
validates_inclusion_of :subscribing_to_email, in: [true, false]
|
|
37
|
+
validate :subscribing_to_email_cannot_be_true_when_subscribing_is_false
|
|
38
|
+
validates :subscribed_at, presence: true, if: :subscribing
|
|
39
|
+
validates :unsubscribed_at, presence: true, unless: :subscribing
|
|
40
|
+
validates :subscribed_to_email_at, presence: true, if: :subscribing_to_email
|
|
41
|
+
validates :unsubscribed_to_email_at, presence: true, unless: :subscribing_to_email
|
|
42
|
+
validate :subscribing_to_optional_target_cannot_be_true_when_subscribing_is_false
|
|
43
|
+
|
|
44
|
+
%i[ filtered_by_association filtered_by_target
|
|
45
|
+
filtered_by_target_type filtered_by_key filtered_by_options
|
|
46
|
+
latest_order earliest_order latest_order! earliest_order!
|
|
47
|
+
latest_subscribed_order earliest_subscribed_order key_order
|
|
48
|
+
reload
|
|
49
|
+
uniq_keys
|
|
50
|
+
].each do |method|
|
|
51
|
+
# Return a criteria chain in response to a method that will begin or end a chain.
|
|
52
|
+
# For more information, see Dynamoid::Criteria::Chain.
|
|
53
|
+
singleton_class.send(:define_method, method) do |*args, &block|
|
|
54
|
+
# Use scan_index_forward with true as default value to convert Dynamoid::Document into Dynamoid::Criteria::Chain
|
|
55
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/document.rb
|
|
56
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/components.rb
|
|
57
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria.rb
|
|
58
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria/chain.rb
|
|
59
|
+
scan_index_forward(true).send(method, *args, &block)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
%i[ with_target ].each do |method|
|
|
64
|
+
singleton_class.send(:define_method, method) do |*args, &block|
|
|
65
|
+
self
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Initialize without options to use Dynamoid.config.store_datetime_as_string
|
|
70
|
+
# https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/dumping.rb
|
|
71
|
+
@@date_time_dumper = ::Dynamoid::Dumping::DateTimeDumper.new({})
|
|
72
|
+
|
|
73
|
+
# Convert Time value to store in database as Hash value.
|
|
74
|
+
# @param [Time] time Time value to store in database as Hash value
|
|
75
|
+
# @return [Integer, String] Converted Time value
|
|
76
|
+
def self.convert_time_as_hash(time)
|
|
77
|
+
@@date_time_dumper.process(time)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|