activity_notification 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +49 -9
- data/activity_notification.gemspec +1 -1
- data/app/controllers/activity_notification/notifications_controller.rb +75 -31
- data/app/mailers/activity_notification/mailer.rb +19 -4
- data/app/views/activity_notification/mailer/default/batch_default.html.erb +79 -0
- data/app/views/activity_notification/mailer/default/batch_default.text.erb +13 -0
- data/app/views/activity_notification/mailer/default/default.html.erb +75 -10
- data/app/views/activity_notification/mailer/default/default.text.erb +2 -2
- data/app/views/activity_notification/notifications/default/_default.html.erb +15 -14
- data/app/views/activity_notification/notifications/default/_default_without_grouping.html.erb +165 -0
- data/app/views/activity_notification/notifications/default/_index.html.erb +8 -4
- data/app/views/activity_notification/notifications/default/destroy.js.erb +2 -2
- data/app/views/activity_notification/notifications/default/index.html.erb +9 -5
- data/app/views/activity_notification/notifications/default/open.js.erb +6 -2
- data/app/views/activity_notification/notifications/default/open_all.js.erb +6 -2
- data/lib/activity_notification/apis/notification_api.rb +42 -9
- data/lib/activity_notification/helpers/view_helpers.rb +48 -19
- data/lib/activity_notification/mailers/helpers.rb +74 -37
- data/lib/activity_notification/models/concerns/target.rb +290 -26
- data/lib/activity_notification/models/notification.rb +85 -29
- data/lib/activity_notification/roles/acts_as_target.rb +4 -2
- data/lib/activity_notification/version.rb +1 -1
- data/spec/concerns/apis/notification_api_spec.rb +46 -0
- data/spec/concerns/models/target_spec.rb +281 -22
- data/spec/controllers/notifications_controller_shared_examples.rb +77 -0
- data/spec/helpers/view_helpers_spec.rb +39 -3
- data/spec/mailers/mailer_spec.rb +54 -1
- data/spec/models/notification_spec.rb +11 -0
- data/spec/rails_app/app/models/user.rb +1 -1
- data/spec/rails_app/app/views/layouts/_header.html.erb +2 -0
- data/spec/rails_app/lib/mailer_previews/mailer_preview.rb +6 -0
- data/spec/roles/acts_as_target_spec.rb +1 -1
- metadata +7 -4
@@ -32,27 +32,36 @@ module ActivityNotification
|
|
32
32
|
#
|
33
33
|
# @param [Object] target Target instance of the rendering notifications
|
34
34
|
# @param [Hash] options Options for rendering notifications
|
35
|
-
# @option options [String, Symbol] :target
|
36
|
-
# @option options [
|
37
|
-
# @option options [String] :
|
38
|
-
# @option options [String] :
|
39
|
-
# @option options [String] :
|
40
|
-
# @option options [String] :
|
41
|
-
# @option options [String] :
|
42
|
-
# @option options [String] :
|
35
|
+
# @option options [String, Symbol] :target (nil) Target type name to find template or i18n text
|
36
|
+
# @option options [Symbol] :index_content (:with_attributes) Option method to load target notification index, [:simple, :unopened_simple, :opened_simple, :with_attributes, :unopened_with_attributes, :opened_with_attributes, :none] are available
|
37
|
+
# @option options [String] :partial_root ("activity_notification/notifications/#{target.to_resources_name}", 'activity_notification/notifications/default') Root path of partial template
|
38
|
+
# @option options [String] :notification_partial ("activity_notification/notifications/#{target.to_resources_name}", controller.target_view_path, 'activity_notification/notifications/default') Partial template name of the notification index content
|
39
|
+
# @option options [String] :layout_root ('layouts') Root path of layout template
|
40
|
+
# @option options [String] :notification_layout (nil) Layout template name of the notification index content
|
41
|
+
# @option options [String] :fallback (nil) Fallback template to use when MissingTemplate is raised. Set :text to use i18n text as fallback.
|
42
|
+
# @option options [String] :partial ('index') Partial template name of the partial index
|
43
|
+
# @option options [String] :layout (nil) Layout template name of the partial index
|
44
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
45
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
46
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
47
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
48
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
49
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
50
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
51
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
52
|
+
# @option options [Array] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
43
53
|
# @return [String] Rendered view or text as string
|
44
54
|
def render_notification_of target, options = {}
|
45
55
|
return unless target.is_a? ActivityNotification::Target
|
46
56
|
|
47
57
|
# Prepare content for notifications index
|
48
|
-
notification_options = options.merge target: target.to_resources_name,
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
58
|
+
notification_options = options.merge( target: target.to_resources_name,
|
59
|
+
partial: options[:notification_partial],
|
60
|
+
layout: options[:notification_layout] )
|
61
|
+
index_options = options.slice( :limit, :reverse, :with_group_members,
|
62
|
+
:filtered_by_group, :filtered_by_group_type, :filtered_by_group_id,
|
63
|
+
:filtered_by_type, :filtered_by_key, :custom_filter )
|
64
|
+
notification_index = load_notification_index(target, options[:index_content], index_options)
|
56
65
|
prepare_content_for(target, notification_index, notification_options)
|
57
66
|
|
58
67
|
# Render partial index
|
@@ -173,6 +182,26 @@ module ActivityNotification
|
|
173
182
|
|
174
183
|
private
|
175
184
|
|
185
|
+
# Load notification index from :index_content parameter
|
186
|
+
# @api private
|
187
|
+
#
|
188
|
+
# @param [Object] target Notification target instance
|
189
|
+
# @param [Symbol] index_content Method to load target notification index, [:simple, :unopened_simple, :opened_simple, :with_attributes, :unopened_with_attributes, :opened_with_attributes, :none] are available
|
190
|
+
# @param [Hash] params Option parameter to load notification index
|
191
|
+
# @return [Array<Notification>] Array of notification index
|
192
|
+
def load_notification_index(target, index_content, options = {})
|
193
|
+
case index_content
|
194
|
+
when :simple then target.notification_index(options)
|
195
|
+
when :unopened_simple then target.unopened_notification_index(options)
|
196
|
+
when :opened_simple then target.opened_notification_index(options)
|
197
|
+
when :with_attributes then target.notification_index_with_attributes(options)
|
198
|
+
when :unopened_with_attributes then target.unopened_notification_index_with_attributes(options)
|
199
|
+
when :opened_with_attributes then target.opened_notification_index_with_attributes(options)
|
200
|
+
when :none then []
|
201
|
+
else target.notification_index_with_attributes(options)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
176
205
|
# Prepare content for notification index
|
177
206
|
# @api private
|
178
207
|
#
|
@@ -194,14 +223,14 @@ module ActivityNotification
|
|
194
223
|
# Render partial index of notifications
|
195
224
|
# @api private
|
196
225
|
#
|
197
|
-
# @param [Object] target
|
198
|
-
# @param [Hash]
|
226
|
+
# @param [Object] target Notification target instance
|
227
|
+
# @param [Hash] params Option parameter to send render
|
199
228
|
# @return [String] Rendered partial index view as string
|
200
229
|
def render_partial_index(target, params)
|
201
230
|
index_path = params.delete(:partial)
|
202
231
|
partial = partial_index_path(target, index_path, params[:partial_root])
|
203
232
|
layout = layout_path(params.delete(:layout), params[:layout_root])
|
204
|
-
locals = (params[:locals] || {}).merge(target: target)
|
233
|
+
locals = (params[:locals] || {}).merge(target: target, parameters: params)
|
205
234
|
begin
|
206
235
|
render params.merge(partial: partial, layout: layout, locals: locals)
|
207
236
|
rescue ActionView::MissingTemplate
|
@@ -10,43 +10,61 @@ module ActivityNotification
|
|
10
10
|
|
11
11
|
# Send notification email with configured options.
|
12
12
|
#
|
13
|
-
# @param [Notification] notification Notification instance
|
14
|
-
# @param [Hash]
|
13
|
+
# @param [Notification] notification Notification instance to send email
|
14
|
+
# @param [Hash] options Options for notification email
|
15
|
+
# @option options [String, Symbol] :fallback (:default) Fallback template to use when MissingTemplate is raised
|
15
16
|
def notification_mail(notification, options = {})
|
16
17
|
initialize_from_notification(notification)
|
17
18
|
headers = headers_for(notification.key, options)
|
18
|
-
|
19
|
-
mail headers
|
20
|
-
rescue ActionView::MissingTemplate => e
|
21
|
-
if options[:fallback].present?
|
22
|
-
mail headers.merge(template_name: options[:fallback])
|
23
|
-
else
|
24
|
-
raise e
|
25
|
-
end
|
26
|
-
end
|
19
|
+
send_mail(headers, options[:fallback])
|
27
20
|
end
|
28
|
-
|
21
|
+
|
22
|
+
# Send batch notification email with configured options.
|
23
|
+
#
|
24
|
+
# @param [Object] target Target of batch notification email
|
25
|
+
# @param [Array<Notification>] notifications Target notifications to send batch notification email
|
26
|
+
# @param [Hash] options Options for notification email
|
27
|
+
# @option options [String, Symbol] :fallback (:batch_default) Fallback template to use when MissingTemplate is raised
|
28
|
+
# @option options [String] :batch_key (nil) Key of the batch notification email, a key of the first notification will be used if not specified
|
29
|
+
def batch_notification_mail(target, notifications, options = {})
|
30
|
+
initialize_from_notifications(target, notifications)
|
31
|
+
batch_key = options.delete(:batch_key)
|
32
|
+
batch_key ||= @notification.key
|
33
|
+
headers = headers_for(batch_key, options)
|
34
|
+
@notification = nil
|
35
|
+
send_mail(headers, options[:fallback])
|
36
|
+
end
|
37
|
+
|
29
38
|
# Initialize instance variables from notification.
|
30
39
|
#
|
31
40
|
# @param [Notification] notification Notification instance
|
32
41
|
def initialize_from_notification(notification)
|
33
|
-
@notification, @target, @
|
42
|
+
@notification, @target, @batch_email = notification, notification.target, false
|
34
43
|
end
|
35
|
-
|
44
|
+
|
45
|
+
# Initialize instance variables from notifications.
|
46
|
+
#
|
47
|
+
# @param [Object] target Target of batch notification email
|
48
|
+
# @param [Array<Notification>] notifications Target notifications to send batch notification email
|
49
|
+
def initialize_from_notifications(target, notifications)
|
50
|
+
@target, @notifications, @notification, @batch_email = target, notifications, notifications.first, true
|
51
|
+
end
|
52
|
+
|
36
53
|
# Prepare email header from notification key and options.
|
37
54
|
#
|
38
55
|
# @param [String] key Key of the notification
|
39
56
|
# @param [Hash] options Options for email notification
|
40
57
|
def headers_for(key, options)
|
41
|
-
if
|
42
|
-
@notifiable.overriding_notification_email_key
|
43
|
-
|
58
|
+
if !@batch_email and
|
59
|
+
@notification.notifiable.respond_to?(:overriding_notification_email_key) and
|
60
|
+
@notification.notifiable.overriding_notification_email_key(@target, key).present?
|
61
|
+
key = @notification.notifiable.overriding_notification_email_key(@target, key)
|
44
62
|
end
|
45
63
|
headers = {
|
46
64
|
subject: subject_for(key),
|
47
65
|
to: mailer_to(@target),
|
48
|
-
from: mailer_from(
|
49
|
-
reply_to: mailer_reply_to(
|
66
|
+
from: mailer_from(key),
|
67
|
+
reply_to: mailer_reply_to(key),
|
50
68
|
template_path: template_paths,
|
51
69
|
template_name: template_name(key)
|
52
70
|
}.merge(options)
|
@@ -54,7 +72,7 @@ module ActivityNotification
|
|
54
72
|
@email = headers[:to]
|
55
73
|
headers
|
56
74
|
end
|
57
|
-
|
75
|
+
|
58
76
|
# Returns target email address as 'to'.
|
59
77
|
#
|
60
78
|
# @param [Object] target Target instance to notify
|
@@ -62,38 +80,38 @@ module ActivityNotification
|
|
62
80
|
def mailer_to(target)
|
63
81
|
target.mailer_to
|
64
82
|
end
|
65
|
-
|
83
|
+
|
66
84
|
# Returns sender email address as 'reply_to'.
|
67
85
|
#
|
68
|
-
# @param [
|
86
|
+
# @param [String] key Key of the notification or batch notification email
|
69
87
|
# @return [String] Sender email address as 'reply_to'
|
70
|
-
def mailer_reply_to(
|
71
|
-
mailer_sender(
|
88
|
+
def mailer_reply_to(key)
|
89
|
+
mailer_sender(key, :reply_to)
|
72
90
|
end
|
73
|
-
|
91
|
+
|
74
92
|
# Returns sender email address as 'from'.
|
75
93
|
#
|
76
|
-
# @param [
|
94
|
+
# @param [String] key Key of the notification or batch notification email
|
77
95
|
# @return [String] Sender email address as 'from'
|
78
|
-
def mailer_from(
|
79
|
-
mailer_sender(
|
96
|
+
def mailer_from(key)
|
97
|
+
mailer_sender(key, :from)
|
80
98
|
end
|
81
|
-
|
99
|
+
|
82
100
|
# Returns sender email address configured in initializer or mailer class.
|
83
101
|
#
|
84
|
-
# @param [
|
102
|
+
# @param [String] key Key of the notification or batch notification email
|
85
103
|
# @return [String] Sender email address configured in initializer or mailer class
|
86
|
-
def mailer_sender(
|
104
|
+
def mailer_sender(key, sender = :from)
|
87
105
|
default_sender = default_params[sender]
|
88
106
|
if default_sender.present?
|
89
107
|
default_sender.respond_to?(:to_proc) ? instance_eval(&default_sender) : default_sender
|
90
108
|
elsif ActivityNotification.config.mailer_sender.is_a?(Proc)
|
91
|
-
ActivityNotification.config.mailer_sender.call(
|
109
|
+
ActivityNotification.config.mailer_sender.call(key)
|
92
110
|
else
|
93
111
|
ActivityNotification.config.mailer_sender
|
94
112
|
end
|
95
113
|
end
|
96
|
-
|
114
|
+
|
97
115
|
# Returns template paths to find email view
|
98
116
|
#
|
99
117
|
# @return [Array<String>] Template paths to find email view
|
@@ -102,7 +120,7 @@ module ActivityNotification
|
|
102
120
|
paths.unshift("activity_notification/mailer/#{@target.to_resources_name}") if @target.present?
|
103
121
|
paths
|
104
122
|
end
|
105
|
-
|
123
|
+
|
106
124
|
# Returns template name from notification key
|
107
125
|
#
|
108
126
|
# @param [String] key Key of the notification
|
@@ -110,8 +128,8 @@ module ActivityNotification
|
|
110
128
|
def template_name(key)
|
111
129
|
key.gsub('.', '/')
|
112
130
|
end
|
113
|
-
|
114
|
-
|
131
|
+
|
132
|
+
|
115
133
|
# Set up a subject doing an I18n lookup.
|
116
134
|
# At first, it attempts to set a subject based on the current mapping:
|
117
135
|
# en:
|
@@ -131,7 +149,26 @@ module ActivityNotification
|
|
131
149
|
k.insert(1, @target.to_resource_name)
|
132
150
|
k = k.join('.')
|
133
151
|
I18n.t(:mail_subject, scope: k,
|
134
|
-
default: ["Notification of #{@notifiable.printable_type.downcase}"])
|
152
|
+
default: ["Notification of #{@notification.notifiable.printable_type.downcase}"])
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
# Send email with fallback option.
|
159
|
+
#
|
160
|
+
# @param [Hash] headers Prepared email header
|
161
|
+
# @param [String, Symbol] fallback Fallback option
|
162
|
+
def send_mail(headers, fallback = nil)
|
163
|
+
begin
|
164
|
+
mail headers
|
165
|
+
rescue ActionView::MissingTemplate => e
|
166
|
+
if fallback.present?
|
167
|
+
mail headers.merge(template_name: fallback)
|
168
|
+
else
|
169
|
+
raise e
|
170
|
+
end
|
171
|
+
end
|
135
172
|
end
|
136
173
|
|
137
174
|
end
|
@@ -15,6 +15,7 @@ module ActivityNotification
|
|
15
15
|
|
16
16
|
class_attribute :_notification_email,
|
17
17
|
:_notification_email_allowed,
|
18
|
+
:_batch_notification_email_allowed,
|
18
19
|
:_notification_devise_resource,
|
19
20
|
:_printable_notification_target_name
|
20
21
|
set_target_class_defaults
|
@@ -32,10 +33,104 @@ module ActivityNotification
|
|
32
33
|
def set_target_class_defaults
|
33
34
|
self._notification_email = nil
|
34
35
|
self._notification_email_allowed = ActivityNotification.config.email_enabled
|
36
|
+
self._batch_notification_email_allowed = ActivityNotification.config.email_enabled
|
35
37
|
self._notification_devise_resource = ->(model) { model }
|
36
38
|
self._printable_notification_target_name = :printable_name
|
37
39
|
nil
|
38
40
|
end
|
41
|
+
|
42
|
+
# Gets all notifications for this target type.
|
43
|
+
#
|
44
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
45
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
46
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
47
|
+
# @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
|
48
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
49
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
50
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
51
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
52
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
53
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
54
|
+
# @return [Array<Notificaion>] All notifications for this target type
|
55
|
+
def all_notifications(options = {})
|
56
|
+
reverse = options[:reverse] || false
|
57
|
+
with_group_members = options[:with_group_members] || false
|
58
|
+
target_notifications = Notification.filtered_by_target_type(self.name)
|
59
|
+
.all_index!(reverse, with_group_members)
|
60
|
+
.filtered_by_options(options)
|
61
|
+
options[:limit].present? ? target_notifications.limit(options[:limit]) : target_notifications
|
62
|
+
end
|
63
|
+
|
64
|
+
# Gets all notifications for this target type grouped by targets.
|
65
|
+
#
|
66
|
+
# @example Get all notifications for for users grouped by user
|
67
|
+
# @notification_index_map = User.notification_index_map
|
68
|
+
# @notification_index_map.each do |user, notifications|
|
69
|
+
# # Do something for user and notifications
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
73
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
74
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
75
|
+
# @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
|
76
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
77
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
78
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
79
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
80
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
81
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
82
|
+
# @return [Array<Notificaion>] All notifications for this target type grouped by targets
|
83
|
+
def notification_index_map(options = {})
|
84
|
+
all_notifications(options).group_by(&:target)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Gets all unopened notifications for this target type grouped by targets.
|
88
|
+
#
|
89
|
+
# @example Get all unopened notifications for users grouped by user
|
90
|
+
# @unopened_notification_index_map = User.unopened_notification_index_map
|
91
|
+
# @unopened_notification_index_map.each do |user, notifications|
|
92
|
+
# # Do something for user and notifications
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
96
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
97
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
98
|
+
# @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
|
99
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
100
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
101
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
102
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
103
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
104
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
105
|
+
# @return [Array<Notificaion>] All unopened notifications for this target type grouped by targets
|
106
|
+
def unopened_notification_index_map(options = {})
|
107
|
+
all_notifications(options).unopened_only.group_by(&:target)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Send batch notification email to this type targets with unopened notifications.
|
111
|
+
#
|
112
|
+
# @example Send batch notification email to the users with unopened notifications of specified key
|
113
|
+
# User.send_batch_unopened_notification_email(filtered_by_key: 'this.key')
|
114
|
+
# @example Send batch notification email to the users with unopened notifications of specified key in 1 hour
|
115
|
+
# User.send_batch_unopened_notification_email(filtered_by_key: 'this.key', custom_filter: ["created_at >= ?", time.hour.ago])
|
116
|
+
#
|
117
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
118
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
119
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
120
|
+
# @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
|
121
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
122
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
123
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
124
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
125
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
126
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
127
|
+
# @return [Hash<Object, Mail::Message|ActionMailer::DeliveryJob>] Hash of target and sent email message or its delivery job
|
128
|
+
def send_batch_unopened_notification_email(options = {})
|
129
|
+
unopened_notification_index_map = unopened_notification_index_map(options)
|
130
|
+
unopened_notification_index_map.map { |target, notifications|
|
131
|
+
[target, Notification.send_batch_notification_email(target, notifications, options)]
|
132
|
+
}.to_h
|
133
|
+
end
|
39
134
|
end
|
40
135
|
|
41
136
|
# Returns target email address for email notification.
|
@@ -56,6 +151,16 @@ module ActivityNotification
|
|
56
151
|
resolve_value(_notification_email_allowed, notifiable, key)
|
57
152
|
end
|
58
153
|
|
154
|
+
# Returns if sending batch notification email is allowed for the target from configured field or overriden method.
|
155
|
+
# This method is able to be overriden.
|
156
|
+
#
|
157
|
+
# @param [Object] notifiable_type Notifiable type of the notifications
|
158
|
+
# @param [String] key Key of the notifications
|
159
|
+
# @return [Boolean] If sending batch notification email is allowed for the target
|
160
|
+
def batch_notification_email_allowed?(notifiable_type, key)
|
161
|
+
resolve_value(_batch_notification_email_allowed, notifiable_type, key)
|
162
|
+
end
|
163
|
+
|
59
164
|
# Returns if current resource signed in with Devise is authenticated for the notification.
|
60
165
|
# This method is able to be overriden.
|
61
166
|
#
|
@@ -81,21 +186,33 @@ module ActivityNotification
|
|
81
186
|
# Returns count of unopened notifications of the target.
|
82
187
|
#
|
83
188
|
# @param [Hash] options Options for notification index
|
84
|
-
# @option options [Integer]
|
189
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
190
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
191
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
192
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
193
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
194
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
195
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
196
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
85
197
|
# @return [Integer] Count of unopened notifications of the target
|
86
|
-
# @todo Add filter and reverse options
|
87
198
|
def unopened_notification_count(options = {})
|
88
|
-
|
199
|
+
target_notifications = _unopened_notification_index(options)
|
200
|
+
target_notifications.present? ? target_notifications.count : 0
|
89
201
|
end
|
90
202
|
|
91
203
|
# Returns if the target has unopened notifications.
|
92
204
|
#
|
93
205
|
# @param [Hash] options Options for notification index
|
94
|
-
# @option options [Integer]
|
206
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
207
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
208
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
209
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
210
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
211
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
212
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
95
213
|
# @return [Boolean] If the target has unopened notifications
|
96
|
-
# @todo Add filter and reverse options
|
97
214
|
def has_unopened_notifications?(options = {})
|
98
|
-
|
215
|
+
_unopened_notification_index(options).present?
|
99
216
|
end
|
100
217
|
|
101
218
|
# Gets automatically arranged notification index of the target.
|
@@ -108,9 +225,17 @@ module ActivityNotification
|
|
108
225
|
# @notifications = @user.notification_index
|
109
226
|
#
|
110
227
|
# @param [Hash] options Options for notification index
|
111
|
-
# @option options [Integer]
|
228
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
229
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
230
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
231
|
+
# @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
|
232
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
233
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
234
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
235
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
236
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
237
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
112
238
|
# @return [Array<Notificaion>] Notification index of the target
|
113
|
-
# @todo Add filter and reverse options
|
114
239
|
def notification_index(options = {})
|
115
240
|
arrange_notification_index(method(:unopened_notification_index),
|
116
241
|
method(:opened_notification_index),
|
@@ -123,13 +248,19 @@ module ActivityNotification
|
|
123
248
|
# @notifications = @user.unopened_notification_index
|
124
249
|
#
|
125
250
|
# @param [Hash] options Options for notification index
|
126
|
-
# @option options [Integer]
|
251
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
252
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
253
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
254
|
+
# @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
|
255
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
256
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
257
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
258
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
259
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
260
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
127
261
|
# @return [Array<Notificaion>] Unopened notification index of the target
|
128
|
-
# @todo Add filter and reverse options
|
129
262
|
def unopened_notification_index(options = {})
|
130
|
-
|
131
|
-
notifications.unopened_index.limit(options[:limit]) :
|
132
|
-
notifications.unopened_index
|
263
|
+
arrange_single_notification_index(method(:_unopened_notification_index), options)
|
133
264
|
end
|
134
265
|
|
135
266
|
# Gets opened notification index of the target.
|
@@ -138,12 +269,19 @@ module ActivityNotification
|
|
138
269
|
# @notifications = @user.opened_notification_index(10)
|
139
270
|
#
|
140
271
|
# @param [Hash] options Options for notification index
|
141
|
-
# @option options [Integer]
|
272
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
273
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
274
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
275
|
+
# @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
|
276
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
277
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
278
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
279
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
280
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
281
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
142
282
|
# @return [Array<Notificaion>] Opened notification index of the target
|
143
|
-
# @todo Add filter and reverse options
|
144
283
|
def opened_notification_index(options = {})
|
145
|
-
|
146
|
-
notifications.opened_index(limit)
|
284
|
+
arrange_single_notification_index(method(:_opened_notification_index), options)
|
147
285
|
end
|
148
286
|
|
149
287
|
# Generates notifications to this target.
|
@@ -190,9 +328,20 @@ module ActivityNotification
|
|
190
328
|
# @notifications = @user.notification_index_with_attributes
|
191
329
|
#
|
192
330
|
# @param [Hash] options Options for notification index
|
193
|
-
# @option options [
|
331
|
+
# @option options [Boolean] :send_later (false) If it sends notification email asynchronously
|
332
|
+
# @option options [String, Symbol] :fallback (:batch_default) Fallback template to use when MissingTemplate is raised
|
333
|
+
# @option options [String] :batch_key (nil) Key of the batch notification email, a key of the first notification will be used if not specified
|
334
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
335
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
336
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
337
|
+
# @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
|
338
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
339
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
340
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
341
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
342
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
343
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
194
344
|
# @return [Array<Notificaion>] Notification index of the target with attributes
|
195
|
-
# @todo Add filter and reverse options
|
196
345
|
def notification_index_with_attributes(options = {})
|
197
346
|
arrange_notification_index(method(:unopened_notification_index_with_attributes),
|
198
347
|
method(:opened_notification_index_with_attributes),
|
@@ -205,11 +354,19 @@ module ActivityNotification
|
|
205
354
|
# @notifications = @user.unopened_notification_index_with_attributes
|
206
355
|
#
|
207
356
|
# @param [Hash] options Options for notification index
|
208
|
-
# @option options [Integer]
|
357
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
358
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
359
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
360
|
+
# @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
|
361
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
362
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
363
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
364
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
365
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
366
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
209
367
|
# @return [Array<Notificaion>] Unopened notification index of the target with attributes
|
210
|
-
# @todo Add filter and reverse options
|
211
368
|
def unopened_notification_index_with_attributes(options = {})
|
212
|
-
include_attributes
|
369
|
+
include_attributes _unopened_notification_index(options)
|
213
370
|
end
|
214
371
|
|
215
372
|
# Gets opened notification index of the target with including attributes like target, notifiable, group and notifier.
|
@@ -218,15 +375,92 @@ module ActivityNotification
|
|
218
375
|
# @notifications = @user.opened_notification_index_with_attributes(10)
|
219
376
|
#
|
220
377
|
# @param [Hash] options Options for notification index
|
221
|
-
# @option options [Integer]
|
378
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
379
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
380
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
381
|
+
# @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
|
382
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
383
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
384
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
385
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
386
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
387
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
222
388
|
# @return [Array<Notificaion>] Opened notification index of the target with attributes
|
223
|
-
# @todo Add filter and reverse options
|
224
389
|
def opened_notification_index_with_attributes(options = {})
|
225
|
-
include_attributes
|
390
|
+
include_attributes _opened_notification_index(options)
|
226
391
|
end
|
227
392
|
|
393
|
+
# Sends notification email to the target.
|
394
|
+
#
|
395
|
+
# @param [Hash] options Options for notification email
|
396
|
+
# @option options [Boolean] :send_later If it sends notification email asynchronously
|
397
|
+
# @option options [String, Symbol] :fallback (:default) Fallback template to use when MissingTemplate is raised
|
398
|
+
# @return [Mail::Message|ActionMailer::DeliveryJob] Email message or its delivery job, return NilClass for wrong target
|
399
|
+
def send_notification_email(notification, options = {})
|
400
|
+
if notification.target == self
|
401
|
+
notification.send_notification_email(options)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
# Sends batch notification email to the target.
|
406
|
+
#
|
407
|
+
# @param [Array<Notification>] notifications Target notifications to send batch notification email
|
408
|
+
# @param [Hash] options Options for notification email
|
409
|
+
# @option options [Boolean] :send_later (false) If it sends notification email asynchronously
|
410
|
+
# @option options [String, Symbol] :fallback (:batch_default) Fallback template to use when MissingTemplate is raised
|
411
|
+
# @option options [String] :batch_key (nil) Key of the batch notification email, a key of the first notification will be used if not specified
|
412
|
+
# @return [Mail::Message|ActionMailer::DeliveryJob|NilClass] Email message or its delivery job, return NilClass for wrong target
|
413
|
+
def send_batch_notification_email(notifications, options = {})
|
414
|
+
return if notifications.blank?
|
415
|
+
if notifications.map{ |n| n.target }.uniq == [self]
|
416
|
+
Notification.send_batch_notification_email(self, notifications, options)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
|
228
421
|
private
|
229
422
|
|
423
|
+
# Gets unopened notification index of the target as ActiveRecord.
|
424
|
+
# @api private
|
425
|
+
#
|
426
|
+
# @param [Hash] options Options for notification index
|
427
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
428
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
429
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
430
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
431
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
432
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
433
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
434
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
435
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
436
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>] Unopened notification index of the target
|
437
|
+
def _unopened_notification_index(options = {})
|
438
|
+
reverse = options[:reverse] || false
|
439
|
+
with_group_members = options[:with_group_members] || false
|
440
|
+
target_index = notifications.unopened_index(reverse, with_group_members).filtered_by_options(options)
|
441
|
+
options[:limit].present? ? target_index.limit(options[:limit]) : target_index
|
442
|
+
end
|
443
|
+
|
444
|
+
# Gets opened notification index of the target as ActiveRecord.
|
445
|
+
#
|
446
|
+
# @param [Hash] options Options for notification index
|
447
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
448
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
449
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
450
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
451
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
452
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
453
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
454
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
455
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
456
|
+
# @return [Array<Notificaion>] Opened notification index of the target
|
457
|
+
def _opened_notification_index(options = {})
|
458
|
+
limit = options[:limit] || ActivityNotification.config.opened_index_limit
|
459
|
+
reverse = options[:reverse] || false
|
460
|
+
with_group_members = options[:with_group_members] || false
|
461
|
+
notifications.opened_index(limit, reverse, with_group_members).filtered_by_options(options)
|
462
|
+
end
|
463
|
+
|
230
464
|
# Includes attributes like target, notifiable, group or notifier from the notification index.
|
231
465
|
# When group member exists in the notification index, group will be included in addition to target, notifiable and or notifier.
|
232
466
|
# Otherwise, target, notifiable and or notifier will be include without group.
|
@@ -244,6 +478,28 @@ module ActivityNotification
|
|
244
478
|
end
|
245
479
|
end
|
246
480
|
|
481
|
+
# Gets arranged single notification index of the target.
|
482
|
+
# @api private
|
483
|
+
#
|
484
|
+
# @param [Method] loading_index_method Method to load index
|
485
|
+
# @param [Hash] options Options for notification index
|
486
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
487
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
488
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
489
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
490
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
491
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
492
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
493
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
494
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
495
|
+
# @return [Array<Notificaion>] Notification index of the target
|
496
|
+
def arrange_single_notification_index(loading_index_method, options = {})
|
497
|
+
as_latest_group_member = options[:as_latest_group_member] || false
|
498
|
+
as_latest_group_member ?
|
499
|
+
loading_index_method.call(options).map{ |n| n.latest_group_member } :
|
500
|
+
loading_index_method.call(options).to_a
|
501
|
+
end
|
502
|
+
|
247
503
|
# Gets automatically arranged notification index of the target.
|
248
504
|
# When the target have unopened notifications, it returns unopened notifications first.
|
249
505
|
# Additionaly, it returns opened notifications unless unopened index size overs the limit.
|
@@ -253,7 +509,15 @@ module ActivityNotification
|
|
253
509
|
# @param [Method] loading_unopened_index_method Method to load unopened index
|
254
510
|
# @param [Method] loading_opened_index_method Method to load opened index
|
255
511
|
# @param [Hash] options Options for notification index
|
256
|
-
# @option options [Integer]
|
512
|
+
# @option options [Integer] :limit (nil) Limit to query for notifications
|
513
|
+
# @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
514
|
+
# @option options [Boolean] :with_group_members (false) If notification index will include group members
|
515
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
516
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
517
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
518
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
519
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
520
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
257
521
|
# @return [Array<Notificaion>] Notification index of the target
|
258
522
|
def arrange_notification_index(loading_unopened_index_method, loading_opened_index_method, options = {})
|
259
523
|
# When the target have unopened notifications
|