activity_notification 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|