activity_notification 2.7.0 → 2.7.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/app/channels/activity_notification/notification_api_channel.rb +2 -0
- data/app/channels/activity_notification/notification_channel.rb +2 -0
- data/app/controllers/activity_notification/notifications_api_controller.rb +0 -1
- data/app/controllers/activity_notification/subscriptions_api_controller.rb +0 -1
- data/app/views/activity_notification/notifications/default/index.html.erb +1 -1
- data/docs/Functions.md +4 -2
- data/lib/activity_notification/common.rb +35 -8
- data/lib/activity_notification/helpers/view_helpers.rb +1 -1
- data/lib/activity_notification/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 56122565c61de552c48285f449429a7d64616f5c13f04f0e023a68b33273db6f
|
|
4
|
+
data.tar.gz: 6462762a8f2d8b7b68b82be0632c1dd3d89379aa7fe904c6f4492053be2633fb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd7b507f00663ebcf26694a0c8c98a0051f51f7bf35e67687a77e668fb61f500f1cf84e2fa433ecbc39bf59357449fcd0cfd0303b107b7e16ea9838d39e3848f
|
|
7
|
+
data.tar.gz: 12cd4b4e589aa66e4ccb6108beb5624d5b13f3d327234491520551c5d9134afabe718367ee3d5193a92e9a1fd2491c9bf5d59250e8e2bb8588c3bcdfaf8565b7
|
|
@@ -4,6 +4,8 @@ class ActivityNotification::NotificationApiChannel < ActivityNotification::Notif
|
|
|
4
4
|
# ActionCable::Channel::Base#subscribed
|
|
5
5
|
# @see https://api.rubyonrails.org/classes/ActionCable/Channel/Base.html#method-i-subscribed
|
|
6
6
|
def subscribed
|
|
7
|
+
# before_subscribe callbacks do not halt the chain on reject
|
|
8
|
+
return if subscription_rejected?
|
|
7
9
|
stream_from "#{ActivityNotification.config.notification_api_channel_prefix}_#{@target.to_class_name}#{ActivityNotification.config.composite_key_delimiter}#{@target.id}"
|
|
8
10
|
rescue
|
|
9
11
|
reject
|
|
@@ -7,6 +7,8 @@ if defined?(ActionCable)
|
|
|
7
7
|
# ActionCable::Channel::Base#subscribed
|
|
8
8
|
# @see https://api.rubyonrails.org/classes/ActionCable/Channel/Base.html#method-i-subscribed
|
|
9
9
|
def subscribed
|
|
10
|
+
# before_subscribe callbacks do not halt the chain on reject
|
|
11
|
+
return if subscription_rejected?
|
|
10
12
|
stream_from "#{ActivityNotification.config.notification_channel_prefix}_#{@target.to_class_name}#{ActivityNotification.config.composite_key_delimiter}#{@target.id}"
|
|
11
13
|
rescue
|
|
12
14
|
reject
|
|
@@ -5,7 +5,6 @@ module ActivityNotification
|
|
|
5
5
|
include Swagger::NotificationsApi
|
|
6
6
|
# Include CommonApiController to select target and define common methods
|
|
7
7
|
include CommonApiController
|
|
8
|
-
protect_from_forgery except: [:open_all]
|
|
9
8
|
rescue_from ActivityNotification::NotifiableNotFoundError, with: :render_notifiable_not_found
|
|
10
9
|
|
|
11
10
|
# Returns notification index of the target.
|
|
@@ -5,7 +5,6 @@ module ActivityNotification
|
|
|
5
5
|
include Swagger::SubscriptionsApi
|
|
6
6
|
# Include CommonApiController to select target and define common methods
|
|
7
7
|
include CommonApiController
|
|
8
|
-
protect_from_forgery except: [:create]
|
|
9
8
|
before_action :set_subscription, except: [:index, :create, :find, :optional_target_names]
|
|
10
9
|
before_action ->{ validate_param(:key) }, only: [:find, :optional_target_names]
|
|
11
10
|
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
</style>
|
|
41
41
|
|
|
42
42
|
<% if @target.notification_action_cable_allowed? %>
|
|
43
|
-
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/push.js/1.0.9/push.min.js"></script>
|
|
43
|
+
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/push.js/1.0.9/push.min.js" integrity="sha512-eiqtDDb4GUVCSqOSOTz/s/eiU4B31GrdSb17aPAA4Lv/Cjc8o+hnDvuNkgXhSI5yHuDvYkuojMaQmrB5JB31XQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
|
44
44
|
<script>
|
|
45
45
|
App.activity_notification = App.cable.subscriptions.create(
|
|
46
46
|
{
|
data/docs/Functions.md
CHANGED
|
@@ -336,6 +336,8 @@ You can also add conditions to filter notifications, like this:
|
|
|
336
336
|
User.send_batch_unopened_notification_email(batch_key: 'batch.comment.post', filtered_by_key: 'comment.post', custom_filter: ["created_at >= ?", time.hour.ago])
|
|
337
337
|
```
|
|
338
338
|
|
|
339
|
+
*custom_filter* accepts an array of a SQL fragment with bind parameters or a hash of conditions. Write it in your application code and never build it from request parameters, since it is passed to the ORM query layer as is. A raw SQL string, an array without bind parameters and MongoDB JavaScript operators (`$where`, `$function` and `$accumulator`) are rejected with `ArgumentError`.
|
|
340
|
+
|
|
339
341
|
#### Batch sender configuration
|
|
340
342
|
|
|
341
343
|
*activity_notification* uses same sender configuration of real-time email notification as batch email sender.
|
|
@@ -1007,7 +1009,7 @@ Then, *activity_notification* will broadcast configured notifications to target
|
|
|
1007
1009
|
You can simply create subscriptions for the specified target in your view like this:
|
|
1008
1010
|
|
|
1009
1011
|
```js
|
|
1010
|
-
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/push.js/1.0.9/push.min.js"></script>
|
|
1012
|
+
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/push.js/1.0.9/push.min.js" integrity="sha512-eiqtDDb4GUVCSqOSOTz/s/eiU4B31GrdSb17aPAA4Lv/Cjc8o+hnDvuNkgXhSI5yHuDvYkuojMaQmrB5JB31XQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
|
1011
1013
|
<script>
|
|
1012
1014
|
App.activity_notification = App.cable.subscriptions.create(
|
|
1013
1015
|
{
|
|
@@ -1045,7 +1047,7 @@ You can simply create subscriptions for the specified target in your view like t
|
|
|
1045
1047
|
or create subscriptions in your single page application with API channels like this:
|
|
1046
1048
|
|
|
1047
1049
|
```js
|
|
1048
|
-
// Vue.js implementation with
|
|
1050
|
+
// Vue.js implementation with a small Action Cable plugin (see spec/rails_app/app/javascript/plugins/action-cable.js)
|
|
1049
1051
|
export default {
|
|
1050
1052
|
// ...
|
|
1051
1053
|
mounted () {
|
|
@@ -47,24 +47,51 @@ module ActivityNotification
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
# MongoDB query operators which execute JavaScript on the database server.
|
|
51
|
+
JAVASCRIPT_QUERY_OPERATORS = %w[$where $function $accumulator].freeze
|
|
52
|
+
|
|
50
53
|
# Validates a :custom_filter value before it is passed to the ORM query layer.
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
54
|
+
# custom_filter is a trusted input written by the application developer and
|
|
55
|
+
# must not be built from request parameters. This validation rejects the forms
|
|
56
|
+
# that run raw SQL or server-side JavaScript:
|
|
57
|
+
# - A String, since ActiveRecord's where treats it as a raw SQL fragment
|
|
58
|
+
# - An Array without bind parameters (e.g. ["1=1"]), which is also a raw SQL fragment
|
|
59
|
+
# - A Hash containing MongoDB JavaScript operators ($where, $function and $accumulator)
|
|
60
|
+
# The supported forms are an Array of a SQL fragment with bind parameters
|
|
61
|
+
# (e.g. ["created_at >= ?", time]) or a Hash of conditions.
|
|
56
62
|
# @param [Array, Hash] custom_filter Custom filter value
|
|
57
63
|
# @return [Array, Hash] The same value when it is safe to use
|
|
58
|
-
# @raise [ArgumentError] When custom_filter is
|
|
64
|
+
# @raise [ArgumentError] When custom_filter is not in the supported forms
|
|
59
65
|
def self.validate_custom_filter(custom_filter)
|
|
60
|
-
|
|
66
|
+
valid =
|
|
67
|
+
case custom_filter
|
|
68
|
+
when Array then custom_filter.size >= 2 && custom_filter.first.is_a?(String)
|
|
69
|
+
when Hash then !contains_javascript_query_operator?(custom_filter)
|
|
70
|
+
else false
|
|
71
|
+
end
|
|
72
|
+
unless valid
|
|
61
73
|
raise ArgumentError,
|
|
62
74
|
":custom_filter must be an array of a SQL fragment and bind parameters " \
|
|
63
|
-
"(e.g. [\"created_at >= ?\", time]) or a hash of conditions
|
|
75
|
+
"(e.g. [\"created_at >= ?\", time]) or a hash of conditions without JavaScript operators"
|
|
64
76
|
end
|
|
65
77
|
custom_filter
|
|
66
78
|
end
|
|
67
79
|
|
|
80
|
+
# Returns whether the value contains MongoDB query operators which execute JavaScript.
|
|
81
|
+
# @param [Object] value Value to check
|
|
82
|
+
# @return [Boolean] Whether the value contains JavaScript query operators
|
|
83
|
+
def self.contains_javascript_query_operator?(value)
|
|
84
|
+
case value
|
|
85
|
+
when Hash
|
|
86
|
+
value.any? { |k, v| JAVASCRIPT_QUERY_OPERATORS.include?(k.to_s) || contains_javascript_query_operator?(v) }
|
|
87
|
+
when Array
|
|
88
|
+
value.any? { |v| contains_javascript_query_operator?(v) }
|
|
89
|
+
else
|
|
90
|
+
false
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
private_class_method :contains_javascript_query_operator?
|
|
94
|
+
|
|
68
95
|
# Casts to indifferent hash
|
|
69
96
|
# @param [ActionController::Parameters, Hash] hash
|
|
70
97
|
# @return [HashWithIndifferentAccess] Converted indifferent hash
|
|
@@ -21,7 +21,7 @@ module ActivityNotification
|
|
|
21
21
|
notifications.render self, options
|
|
22
22
|
elsif notifications.respond_to?(:map)
|
|
23
23
|
return nil if (notifications.respond_to?(:empty?) ? notifications.empty? : notifications.to_a.empty?)
|
|
24
|
-
notifications.map {|notification| notification.render self, options.dup }
|
|
24
|
+
safe_join(notifications.map {|notification| notification.render self, options.dup })
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
alias_method :render_notifications, :render_notification
|