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
data/gemfiles/Gemfile.rails-5.0
CHANGED
|
@@ -3,6 +3,7 @@ source 'https://rubygems.org'
|
|
|
3
3
|
gemspec path: '../'
|
|
4
4
|
|
|
5
5
|
gem 'rails', '~> 5.0.0'
|
|
6
|
+
gem 'sqlite3', '~> 1.3.13'
|
|
6
7
|
|
|
7
8
|
group :development do
|
|
8
9
|
gem 'bullet'
|
|
@@ -10,6 +11,7 @@ end
|
|
|
10
11
|
|
|
11
12
|
group :test do
|
|
12
13
|
gem 'rails-controller-testing'
|
|
14
|
+
gem 'action-cable-testing'
|
|
13
15
|
gem 'ammeter'
|
|
14
16
|
gem 'timecop'
|
|
15
17
|
gem 'coveralls', require: false
|
data/gemfiles/Gemfile.rails-5.1
CHANGED
data/gemfiles/Gemfile.rails-5.2
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
source 'https://rubygems.org'
|
|
2
|
+
|
|
3
|
+
gemspec path: '../'
|
|
4
|
+
|
|
5
|
+
gem 'rails', '~> 6.0.0.rc2'
|
|
6
|
+
|
|
7
|
+
group :development do
|
|
8
|
+
gem 'bullet'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
group :test do
|
|
12
|
+
#TODO https://github.com/rails/rails/issues/35417
|
|
13
|
+
gem 'rspec-rails', git: 'https://github.com/rspec/rspec-rails', branch: '4-0-dev'
|
|
14
|
+
|
|
15
|
+
gem 'rails-controller-testing'
|
|
16
|
+
gem 'ammeter'
|
|
17
|
+
gem 'timecop'
|
|
18
|
+
gem 'coveralls', require: false
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
gem 'dotenv-rails', groups: [:development, :test]
|
|
@@ -56,6 +56,7 @@ module ActivityNotification
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
# Load ActivityNotification helpers
|
|
59
|
+
require 'activity_notification/helpers/errors'
|
|
59
60
|
require 'activity_notification/helpers/polymorphic_helpers'
|
|
60
61
|
require 'activity_notification/helpers/view_helpers'
|
|
61
62
|
require 'activity_notification/controllers/common_controller'
|
|
@@ -10,130 +10,187 @@ module ActivityNotification
|
|
|
10
10
|
# Defines mailer class to send notification
|
|
11
11
|
set_notification_mailer
|
|
12
12
|
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
reverse
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
reverse
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
reverse
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
options
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
filtered_notifications =
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
13
|
+
# :only-rails5-plus#only-rails-with-callback-issue#except-dynamoid:
|
|
14
|
+
# :only-rails5-plus#only-rails-without-callback-issue#except-dynamoid:
|
|
15
|
+
# :except-rails5-plus#only-rails-with-callback-issue#except-dynamoid:
|
|
16
|
+
# :except-rails5-plus#only-rails-without-callback-issue#except-dynamoid:
|
|
17
|
+
unless ActivityNotification.config.orm == :dynamoid
|
|
18
|
+
# Selects all notification index.
|
|
19
|
+
# ActivityNotification::Notification.all_index!
|
|
20
|
+
# is defined same as
|
|
21
|
+
# ActivityNotification::Notification.group_owners_only.latest_order
|
|
22
|
+
# @scope class
|
|
23
|
+
# @example Get all notification index of the @user
|
|
24
|
+
# @notifications = @user.notifications.all_index!
|
|
25
|
+
# @notifications = @user.notifications.group_owners_only.latest_order
|
|
26
|
+
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
|
27
|
+
# @param [Boolean] with_group_members If notification index will include group members
|
|
28
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
|
29
|
+
scope :all_index!, ->(reverse = false, with_group_members = false) {
|
|
30
|
+
target_index = with_group_members ? self : group_owners_only
|
|
31
|
+
reverse ? target_index.earliest_order : target_index.latest_order
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Selects unopened notification index.
|
|
35
|
+
# ActivityNotification::Notification.unopened_index
|
|
36
|
+
# is defined same as
|
|
37
|
+
# ActivityNotification::Notification.unopened_only.group_owners_only.latest_order
|
|
38
|
+
# @scope class
|
|
39
|
+
# @example Get unopened notificaton index of the @user
|
|
40
|
+
# @notifications = @user.notifications.unopened_index
|
|
41
|
+
# @notifications = @user.notifications.unopened_only.group_owners_only.latest_order
|
|
42
|
+
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
|
43
|
+
# @param [Boolean] with_group_members If notification index will include group members
|
|
44
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
|
45
|
+
scope :unopened_index, ->(reverse = false, with_group_members = false) {
|
|
46
|
+
target_index = with_group_members ? unopened_only : unopened_only.group_owners_only
|
|
47
|
+
reverse ? target_index.earliest_order : target_index.latest_order
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Selects unopened notification index.
|
|
51
|
+
# ActivityNotification::Notification.opened_index(limit)
|
|
52
|
+
# is defined same as
|
|
53
|
+
# ActivityNotification::Notification.opened_only(limit).group_owners_only.latest_order
|
|
54
|
+
# @scope class
|
|
55
|
+
# @example Get unopened notificaton index of the @user with limit 10
|
|
56
|
+
# @notifications = @user.notifications.opened_index(10)
|
|
57
|
+
# @notifications = @user.notifications.opened_only(10).group_owners_only.latest_order
|
|
58
|
+
# @param [Integer] limit Limit to query for opened notifications
|
|
59
|
+
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
|
60
|
+
# @param [Boolean] with_group_members If notification index will include group members
|
|
61
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
|
62
|
+
scope :opened_index, ->(limit, reverse = false, with_group_members = false) {
|
|
63
|
+
target_index = with_group_members ? opened_only(limit) : opened_only(limit).group_owners_only
|
|
64
|
+
reverse ? target_index.earliest_order : target_index.latest_order
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# Selects filtered notifications by target_type.
|
|
68
|
+
# @example Get filtered unopened notificatons of User as target type
|
|
69
|
+
# @notifications = ActivityNotification.Notification.unopened_only.filtered_by_target_type('User')
|
|
70
|
+
# @scope class
|
|
71
|
+
# @param [String] target_type Target type for filter
|
|
72
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
|
73
|
+
scope :filtered_by_target_type, ->(target_type) { where(target_type: target_type) }
|
|
74
|
+
|
|
75
|
+
# Selects filtered notifications by notifiable_type.
|
|
76
|
+
# @example Get filtered unopened notificatons of the @user for Comment notifiable class
|
|
77
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_type('Comment')
|
|
78
|
+
# @scope class
|
|
79
|
+
# @param [String] notifiable_type Notifiable type for filter
|
|
80
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
|
81
|
+
scope :filtered_by_type, ->(notifiable_type) { where(notifiable_type: notifiable_type) }
|
|
82
|
+
|
|
83
|
+
# Selects filtered notifications by key.
|
|
84
|
+
# @example Get filtered unopened notificatons of the @user with key 'comment.reply'
|
|
85
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_key('comment.reply')
|
|
86
|
+
# @scope class
|
|
87
|
+
# @param [String] key Key of the notification for filter
|
|
88
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
|
89
|
+
scope :filtered_by_key, ->(key) { where(key: key) }
|
|
90
|
+
|
|
91
|
+
# Selects filtered notifications by notifiable_type, group or key with filter options.
|
|
92
|
+
# @example Get filtered unopened notificatons of the @user for Comment notifiable class
|
|
93
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment' })
|
|
94
|
+
# @example Get filtered unopened notificatons of the @user for @article as group
|
|
95
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group: @article })
|
|
96
|
+
# @example Get filtered unopened notificatons of the @user for Article instance id=1 as group
|
|
97
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group_type: 'Article', filtered_by_group_id: '1' })
|
|
98
|
+
# @example Get filtered unopened notificatons of the @user with key 'comment.reply'
|
|
99
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_key: 'comment.reply' })
|
|
100
|
+
# @example Get filtered unopened notificatons of the @user for Comment notifiable class with key 'comment.reply'
|
|
101
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment', filtered_by_key: 'comment.reply' })
|
|
102
|
+
# @example Get custom filtered notificatons of the @user
|
|
103
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ custom_filter: ["created_at >= ?", time.hour.ago] })
|
|
104
|
+
# @scope class
|
|
105
|
+
# @param [Hash] options Options for filter
|
|
106
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
|
107
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
|
108
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
|
109
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
|
110
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
|
111
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago] with ActiveRecord or {:created_at.gt => time.hour.ago} with Mongoid)
|
|
112
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
|
113
|
+
scope :filtered_by_options, ->(options = {}) {
|
|
114
|
+
options = ActivityNotification.cast_to_indifferent_hash(options)
|
|
115
|
+
filtered_notifications = all
|
|
116
|
+
if options.has_key?(:filtered_by_type)
|
|
117
|
+
filtered_notifications = filtered_notifications.filtered_by_type(options[:filtered_by_type])
|
|
118
|
+
end
|
|
119
|
+
if options.has_key?(:filtered_by_group)
|
|
120
|
+
filtered_notifications = filtered_notifications.filtered_by_group(options[:filtered_by_group])
|
|
121
|
+
end
|
|
122
|
+
if options.has_key?(:filtered_by_group_type) && options.has_key?(:filtered_by_group_id)
|
|
123
|
+
filtered_notifications = filtered_notifications
|
|
124
|
+
.where(group_type: options[:filtered_by_group_type], group_id: options[:filtered_by_group_id])
|
|
125
|
+
end
|
|
126
|
+
if options.has_key?(:filtered_by_key)
|
|
127
|
+
filtered_notifications = filtered_notifications.filtered_by_key(options[:filtered_by_key])
|
|
128
|
+
end
|
|
129
|
+
if options.has_key?(:custom_filter)
|
|
130
|
+
filtered_notifications = filtered_notifications.where(options[:custom_filter])
|
|
131
|
+
end
|
|
132
|
+
filtered_notifications
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# Orders by latest (newest) first as created_at: :desc.
|
|
136
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of notifications ordered by latest first
|
|
137
|
+
scope :latest_order, -> { order(created_at: :desc) }
|
|
138
|
+
|
|
139
|
+
# Orders by earliest (older) first as created_at: :asc.
|
|
140
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of notifications ordered by earliest first
|
|
141
|
+
scope :earliest_order, -> { order(created_at: :asc) }
|
|
142
|
+
|
|
143
|
+
# Orders by latest (newest) first as created_at: :desc.
|
|
144
|
+
# This method is to be overridden in implementation for each ORM.
|
|
145
|
+
# @param [Boolean] reverse If notifications will be ordered as earliest first
|
|
146
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of ordered notifications
|
|
147
|
+
scope :latest_order!, ->(reverse = false) { reverse ? earliest_order : latest_order }
|
|
148
|
+
|
|
149
|
+
# Orders by earliest (older) first as created_at: :asc.
|
|
150
|
+
# This method is to be overridden in implementation for each ORM.
|
|
151
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of notifications ordered by earliest first
|
|
152
|
+
scope :earliest_order!, -> { earliest_order }
|
|
153
|
+
|
|
154
|
+
# Returns latest notification instance.
|
|
155
|
+
# @return [Notification] Latest notification instance
|
|
156
|
+
def self.latest
|
|
157
|
+
latest_order.first
|
|
120
158
|
end
|
|
121
|
-
|
|
122
|
-
|
|
159
|
+
|
|
160
|
+
# Returns earliest notification instance.
|
|
161
|
+
# @return [Notification] Earliest notification instance
|
|
162
|
+
def self.earliest
|
|
163
|
+
earliest_order.first
|
|
123
164
|
end
|
|
124
|
-
|
|
125
|
-
|
|
165
|
+
|
|
166
|
+
# Returns latest notification instance.
|
|
167
|
+
# This method is to be overridden in implementation for each ORM.
|
|
168
|
+
# @return [Notification] Latest notification instance
|
|
169
|
+
def self.latest!
|
|
170
|
+
latest
|
|
126
171
|
end
|
|
127
|
-
filtered_notifications
|
|
128
|
-
}
|
|
129
172
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
173
|
+
# Returns earliest notification instance.
|
|
174
|
+
# This method is to be overridden in implementation for each ORM.
|
|
175
|
+
# @return [Notification] Earliest notification instance
|
|
176
|
+
def self.earliest!
|
|
177
|
+
earliest
|
|
178
|
+
end
|
|
133
179
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
180
|
+
# Selects unique keys from query for notifications.
|
|
181
|
+
# @return [Array<String>] Array of notification unique keys
|
|
182
|
+
def self.uniq_keys
|
|
183
|
+
## select method cannot be chained with order by other columns like created_at
|
|
184
|
+
# select(:key).distinct.pluck(:key)
|
|
185
|
+
## distinct method cannot keep original sort
|
|
186
|
+
# distinct(:key)
|
|
187
|
+
pluck(:key).uniq
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
# :only-rails5-plus#only-rails-with-callback-issue#except-dynamoid:
|
|
191
|
+
# :only-rails5-plus#only-rails-without-callback-issue#except-dynamoid:
|
|
192
|
+
# :except-rails5-plus#only-rails-with-callback-issue#except-dynamoid:
|
|
193
|
+
# :except-rails5-plus#only-rails-without-callback-issue#except-dynamoid:
|
|
137
194
|
end
|
|
138
195
|
|
|
139
196
|
class_methods do
|
|
@@ -160,6 +217,8 @@ module ActivityNotification
|
|
|
160
217
|
# @option options [Boolean] :notify_later (false) Whether it generates notifications asynchronously
|
|
161
218
|
# @option options [Boolean] :send_email (true) Whether it sends notification email
|
|
162
219
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
220
|
+
# @option options [Boolean] :broadcast_action_cable (true) Whether it broadcasts notification to ActionCable channel
|
|
221
|
+
# @option options [Hash] :action_cable_rendering ({fallback: :default}) Options for rendering params used by ActionCable, e.g. {fallback: :text} or {fallback: :default} etc. See also Renderable#render.
|
|
163
222
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
164
223
|
# @option options [Boolean] :pass_full_options (false) Whether it passes full options to notifiable.notification_targets, not a key only
|
|
165
224
|
# @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
|
|
@@ -198,6 +257,8 @@ module ActivityNotification
|
|
|
198
257
|
# @option options [Hash] :parameters ({}) Additional parameters of the notifications
|
|
199
258
|
# @option options [Boolean] :send_email (true) Whether it sends notification email
|
|
200
259
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
260
|
+
# @option options [Boolean] :broadcast_action_cable (true) Whether it broadcasts notification to ActionCable channel
|
|
261
|
+
# @option options [Hash] :action_cable_rendering ({fallback: :default}) Options for rendering params used by ActionCable, e.g. {fallback: :text} or {fallback: :default} etc. See also Renderable#render.
|
|
201
262
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
202
263
|
# @option options [Boolean] :pass_full_options (false) Whether it passes full options to notifiable.notification_targets, not a key only
|
|
203
264
|
# @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
|
|
@@ -224,6 +285,8 @@ module ActivityNotification
|
|
|
224
285
|
# @option options [Boolean] :notify_later (false) Whether it generates notifications asynchronously
|
|
225
286
|
# @option options [Boolean] :send_email (true) Whether it sends notification email
|
|
226
287
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
288
|
+
# @option options [Boolean] :broadcast_action_cable (true) Whether it broadcasts notification to ActionCable channel
|
|
289
|
+
# @option options [Hash] :action_cable_rendering ({fallback: :default}) Options for rendering params used by ActionCable, e.g. {fallback: :text} or {fallback: :default} etc. See also Renderable#render.
|
|
227
290
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
228
291
|
# @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
|
|
229
292
|
# @return [Array<Notificaion>] Array of generated notifications
|
|
@@ -251,6 +314,8 @@ module ActivityNotification
|
|
|
251
314
|
# @option options [Hash] :parameters ({}) Additional parameters of the notifications
|
|
252
315
|
# @option options [Boolean] :send_email (true) Whether it sends notification email
|
|
253
316
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
317
|
+
# @option options [Boolean] :broadcast_action_cable (true) Whether it broadcasts notification to ActionCable channel
|
|
318
|
+
# @option options [Hash] :action_cable_rendering ({fallback: :default}) Options for rendering params used by ActionCable, e.g. {fallback: :text} or {fallback: :default} etc. See also Renderable#render.
|
|
254
319
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
255
320
|
# @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
|
|
256
321
|
# @return [Array<Notificaion>] Array of generated notifications
|
|
@@ -275,6 +340,8 @@ module ActivityNotification
|
|
|
275
340
|
# @option options [Boolean] :notify_later (false) Whether it generates notifications asynchronously
|
|
276
341
|
# @option options [Boolean] :send_email (true) Whether it sends notification email
|
|
277
342
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
343
|
+
# @option options [Boolean] :broadcast_action_cable (true) Whether it broadcasts notification to ActionCable channel
|
|
344
|
+
# @option options [Hash] :action_cable_rendering ({fallback: :default}) Options for rendering params used by ActionCable, e.g. {fallback: :text} or {fallback: :default} etc. See also Renderable#render.
|
|
278
345
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
279
346
|
# @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
|
|
280
347
|
# @return [Notification] Generated notification instance
|
|
@@ -282,8 +349,9 @@ module ActivityNotification
|
|
|
282
349
|
if options[:notify_later]
|
|
283
350
|
notify_later_to(target, notifiable, options)
|
|
284
351
|
else
|
|
285
|
-
send_email
|
|
286
|
-
send_later
|
|
352
|
+
send_email = options.has_key?(:send_email) ? options[:send_email] : true
|
|
353
|
+
send_later = options.has_key?(:send_later) ? options[:send_later] : true
|
|
354
|
+
broadcast_action_cable = options.has_key?(:broadcast_action_cable) ? options[:broadcast_action_cable] : true
|
|
287
355
|
publish_optional_targets = options.has_key?(:publish_optional_targets) ? options[:publish_optional_targets] : true
|
|
288
356
|
# Generate notification
|
|
289
357
|
notification = generate_notification(target, notifiable, options)
|
|
@@ -291,6 +359,12 @@ module ActivityNotification
|
|
|
291
359
|
if notification.present? && send_email
|
|
292
360
|
notification.send_notification_email({ send_later: send_later })
|
|
293
361
|
end
|
|
362
|
+
# Broadcast to ActionCable subscribers
|
|
363
|
+
if notification.present? && broadcast_action_cable
|
|
364
|
+
action_cable_rendering_options = options[:action_cable_rendering] || {}
|
|
365
|
+
action_cable_rendering_options[:fallback] = action_cable_rendering_options[:fallback] || :default
|
|
366
|
+
notification.broadcast_to_action_cable_channel(action_cable_rendering_options)
|
|
367
|
+
end
|
|
294
368
|
# Publish to optional targets
|
|
295
369
|
if notification.present? && publish_optional_targets
|
|
296
370
|
notification.publish_to_optional_targets(options[:optional_targets] || {})
|
|
@@ -316,6 +390,8 @@ module ActivityNotification
|
|
|
316
390
|
# @option options [Hash] :parameters ({}) Additional parameters of the notifications
|
|
317
391
|
# @option options [Boolean] :send_email (true) Whether it sends notification email
|
|
318
392
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
393
|
+
# @option options [Boolean] :broadcast_action_cable (true) Whether it broadcast∂s notification to ActionCable channel
|
|
394
|
+
# @option options [Hash] :action_cable_rendering ({fallback: :default}) Options for rendering params used by ActionCable, e.g. {fallback: :text} or {fallback: :default} etc. See also Renderable#render.
|
|
319
395
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
320
396
|
# @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
|
|
321
397
|
# @return [Notification] Generated notification instance
|
|
@@ -336,7 +412,7 @@ module ActivityNotification
|
|
|
336
412
|
key = options[:key] || notifiable.default_notification_key
|
|
337
413
|
if target.subscribes_to_notification?(key)
|
|
338
414
|
# Store notification
|
|
339
|
-
store_notification(target, notifiable, key, options)
|
|
415
|
+
notification = store_notification(target, notifiable, key, options)
|
|
340
416
|
end
|
|
341
417
|
end
|
|
342
418
|
|
|
@@ -366,7 +442,7 @@ module ActivityNotification
|
|
|
366
442
|
# @param [Array<Notificaion>, ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] notifications Array or database query of the notifications to test member exists
|
|
367
443
|
# @return [Boolean] If group member of the notifications exists
|
|
368
444
|
def group_member_exists?(notifications)
|
|
369
|
-
notifications.present?
|
|
445
|
+
notifications.present? and group_members_of_owner_ids_only(notifications.map(&:id)).exists?
|
|
370
446
|
end
|
|
371
447
|
|
|
372
448
|
# Sends batch notification email to the target.
|
|
@@ -394,7 +470,7 @@ module ActivityNotification
|
|
|
394
470
|
#
|
|
395
471
|
# @return [Array<Notificaion>] Available options for kinds of notify methods
|
|
396
472
|
def available_options
|
|
397
|
-
[:key, :group, :
|
|
473
|
+
[:key, :group, :group_expiry_delay, :notifier, :parameters, :send_email, :send_later].freeze
|
|
398
474
|
end
|
|
399
475
|
|
|
400
476
|
# Defines mailer class to send notification
|
|
@@ -402,6 +478,25 @@ module ActivityNotification
|
|
|
402
478
|
@@notification_mailer = ActivityNotification.config.mailer.constantize
|
|
403
479
|
end
|
|
404
480
|
|
|
481
|
+
# Returns valid group owner within the expiration period
|
|
482
|
+
#
|
|
483
|
+
# @param [Object] target Target to send notifications
|
|
484
|
+
# @param [Object] notifiable Notifiable instance
|
|
485
|
+
# @param [String] key Key of the notification
|
|
486
|
+
# @param [Object] group Group unit of the notifications
|
|
487
|
+
# @param [ActiveSupport::Duration] group_expiry_delay Expiry period of a notification group
|
|
488
|
+
# @return [Notificaion] Valid group owner within the expiration period
|
|
489
|
+
def valid_group_owner(target, notifiable, key, group, group_expiry_delay)
|
|
490
|
+
return nil if group.blank?
|
|
491
|
+
# Bundle notification group by target, notifiable_type, group and key
|
|
492
|
+
# Different notifiable.id can be made in a same group
|
|
493
|
+
group_owner_notifications = filtered_by_target(target).filtered_by_type(notifiable.to_class_name).filtered_by_key(key)
|
|
494
|
+
.filtered_by_group(group).group_owners_only.unopened_only
|
|
495
|
+
group_expiry_delay.present? ?
|
|
496
|
+
group_owner_notifications.within_expiration_only(group_expiry_delay).earliest :
|
|
497
|
+
group_owner_notifications.earliest
|
|
498
|
+
end
|
|
499
|
+
|
|
405
500
|
# Stores notifications to datastore
|
|
406
501
|
# @api private
|
|
407
502
|
def store_notification(target, notifiable, key, options = {})
|
|
@@ -412,20 +507,20 @@ module ActivityNotification
|
|
|
412
507
|
parameters = options[:parameters] || {}
|
|
413
508
|
parameters.merge!(options.except(*available_options))
|
|
414
509
|
parameters.merge!(notifiable.notification_parameters(target_type, key))
|
|
510
|
+
group_owner = valid_group_owner(target, notifiable, key, group, group_expiry_delay)
|
|
415
511
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
.filtered_by_group(group).group_owners_only.unopened_only
|
|
420
|
-
group_owner = group_expiry_delay.present? ?
|
|
421
|
-
group_owner_notifications.within_expiration_only(group_expiry_delay).earliest :
|
|
422
|
-
group_owner_notifications.earliest
|
|
423
|
-
notification_fields = { target: target, notifiable: notifiable, key: key, group: group, parameters: parameters, notifier: notifier }
|
|
424
|
-
notification_fields = notification_fields.merge(group_owner: group_owner) if group.present? && group_owner.present?
|
|
425
|
-
create(notification_fields)
|
|
512
|
+
notification = new({ target: target, notifiable: notifiable, key: key, group: group, parameters: parameters, notifier: notifier, group_owner: group_owner })
|
|
513
|
+
notification.prepare_to_store.save
|
|
514
|
+
notification
|
|
426
515
|
end
|
|
427
516
|
end
|
|
428
517
|
|
|
518
|
+
# Returns prepared notification object to store
|
|
519
|
+
# @return [Object] prepared notification object to store
|
|
520
|
+
def prepare_to_store
|
|
521
|
+
self
|
|
522
|
+
end
|
|
523
|
+
|
|
429
524
|
# Sends notification email to the target.
|
|
430
525
|
#
|
|
431
526
|
# @param [Hash] options Options for notification email
|
|
@@ -443,6 +538,64 @@ module ActivityNotification
|
|
|
443
538
|
end
|
|
444
539
|
end
|
|
445
540
|
|
|
541
|
+
# :only-rails5-plus#only-rails-with-callback-issue:
|
|
542
|
+
# :only-rails5-plus#only-rails-without-callback-issue:
|
|
543
|
+
# :only-rails5-plus#only-rails-with-callback-issue#except-dynamoid:
|
|
544
|
+
# :only-rails5-plus#only-rails-without-callback-issue#except-dynamoid:
|
|
545
|
+
if Rails::VERSION::MAJOR >= 5
|
|
546
|
+
# Broadcast to ActionCable subscribers
|
|
547
|
+
# @param [Hash] params Parameters for rendering notifications
|
|
548
|
+
# @option params [String, Symbol] :target (nil) Target type name to find template or i18n text
|
|
549
|
+
# @option params [String] :partial_root ("activity_notification/notifications/#{target}", controller.target_view_path, 'activity_notification/notifications/default') Partial template name
|
|
550
|
+
# @option params [String] :partial (self.key.tr('.', '/')) Root path of partial template
|
|
551
|
+
# @option params [String] :layout (nil) Layout template name
|
|
552
|
+
# @option params [String] :layout_root ('layouts') Root path of layout template
|
|
553
|
+
# @option params [String, Symbol] :fallback (nil) Fallback template to use when MissingTemplate is raised. Set :text to use i18n text as fallback.
|
|
554
|
+
# @option params [String] :filter (nil) Filter option to load notification index (Nothing as auto, 'opened' or 'unopened')
|
|
555
|
+
# @option params [String] :limit (nil) Limit to query for notifications
|
|
556
|
+
# @option params [String] :without_grouping ('false') If notification index will include group members
|
|
557
|
+
# @option params [String] :with_group_members ('false') If notification index will include group members
|
|
558
|
+
# @option params [String] :filtered_by_type (nil) Notifiable type for filter
|
|
559
|
+
# @option params [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
|
560
|
+
# @option params [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
|
561
|
+
# @option params [String] :filtered_by_key (nil) Key of the notification for filter
|
|
562
|
+
# @option params [Hash] others Parameters to be set as locals
|
|
563
|
+
def broadcast_to_action_cable_channel(params = {})
|
|
564
|
+
if target.notification_action_cable_allowed?(notifiable, key) &&
|
|
565
|
+
notifiable.notification_action_cable_allowed?(target, key)
|
|
566
|
+
target_channel_name = "#{ActivityNotification.config.notification_channel_prefix}_#{target_type}#{ActivityNotification.config.composite_key_delimiter}#{target_id}"
|
|
567
|
+
index_options = params.slice(:filter, :limit, :without_grouping, :with_group_members, :filtered_by_type, :filtered_by_group_type, :filtered_by_group_id, :filtered_by_key)
|
|
568
|
+
ActionCable.server.broadcast(target_channel_name,
|
|
569
|
+
id: id,
|
|
570
|
+
view: render(ActivityNotification::NotificationsController.renderer, params),
|
|
571
|
+
text: text(params),
|
|
572
|
+
notifiable_path: notifiable_path,
|
|
573
|
+
group_owner_id: group_owner_id,
|
|
574
|
+
group_owner_view: group_owner? ? nil : group_owner.render(ActivityNotification::NotificationsController.renderer, params),
|
|
575
|
+
unopened_notification_count: target.unopened_notification_count(index_options)
|
|
576
|
+
)
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
# :only-rails5-plus#only-rails-with-callback-issue:
|
|
580
|
+
# :only-rails5-plus#only-rails-without-callback-issue:
|
|
581
|
+
# :only-rails5-plus#only-rails-with-callback-issue#except-dynamoid:
|
|
582
|
+
# :only-rails5-plus#only-rails-without-callback-issue#except-dynamoid:
|
|
583
|
+
# :except-rails5-plus#only-rails-with-callback-issue:
|
|
584
|
+
# :except-rails5-plus#only-rails-without-callback-issue:
|
|
585
|
+
# :except-rails5-plus#only-rails-with-callback-issue#except-dynamoid:
|
|
586
|
+
# :except-rails5-plus#only-rails-without-callback-issue#except-dynamoid:
|
|
587
|
+
else
|
|
588
|
+
# Broadcast to ActionCable subscribers
|
|
589
|
+
# Do nothing with Rails < 5.0
|
|
590
|
+
# @param [Hash] params Parameters for rendering notifications
|
|
591
|
+
def broadcast_to_action_cable_channel(params = {})
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
# :except-rails5-plus#only-rails-with-callback-issue:
|
|
595
|
+
# :except-rails5-plus#only-rails-without-callback-issue:
|
|
596
|
+
# :except-rails5-plus#only-rails-with-callback-issue#except-dynamoid:
|
|
597
|
+
# :except-rails5-plus#only-rails-without-callback-issue#except-dynamoid:
|
|
598
|
+
|
|
446
599
|
# Publishes notification to the optional targets.
|
|
447
600
|
#
|
|
448
601
|
# @param [Hash] options Options for optional targets
|
|
@@ -611,13 +764,13 @@ module ActivityNotification
|
|
|
611
764
|
target.subscribes_to_optional_target?(key, optional_target_name)
|
|
612
765
|
end
|
|
613
766
|
|
|
614
|
-
# Returns optional_targets of the notification from configured field or
|
|
767
|
+
# Returns optional_targets of the notification from configured field or overridden method.
|
|
615
768
|
# @return [Array<ActivityNotification::OptionalTarget::Base>] Array of optional target instances
|
|
616
769
|
def optional_targets
|
|
617
770
|
notifiable.optional_targets(target.to_resources_name, key)
|
|
618
771
|
end
|
|
619
772
|
|
|
620
|
-
# Returns optional_target names of the notification from configured field or
|
|
773
|
+
# Returns optional_target names of the notification from configured field or overridden method.
|
|
621
774
|
# @return [Array<Symbol>] Array of optional target names
|
|
622
775
|
def optional_target_names
|
|
623
776
|
notifiable.optional_target_names(target.to_resources_name, key)
|