noticed 1.5.5 → 1.5.6
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/README.md +27 -0
- data/lib/noticed/delivery_methods/base.rb +15 -8
- data/lib/noticed/delivery_methods/fcm.rb +92 -0
- data/lib/noticed/delivery_methods/ios.rb +2 -2
- data/lib/noticed/version.rb +1 -1
- data/lib/noticed.rb +1 -0
- data/lib/rails_6_polyfills/base.rb +3 -3
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85a89c655531764a6b6c97213a6b1368c21bee48e55298cb35be1154c32534ff
|
4
|
+
data.tar.gz: 404987e57e6f834fe21dc9b895664643767ed08e0d23e05c32cb31ebe0a8c5ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2cd89b9b0d0c0b76792861aba31db3402effab9136574425abfa44cb26130be894166834b1d80aca357c7d811c81d9f32dc5d5f4ad2e8bb68096310c9a8a7a1e
|
7
|
+
data.tar.gz: ec0b3c75c8976cd3e4789e54ca8d1744dad95d118f3c4d20a648153422425f03b8a34f1a5b16ed583db85eb3bfe778c996d354d168ac32765421b8a0bd33b8c6
|
data/README.md
CHANGED
@@ -16,6 +16,7 @@ Currently, we support these notification delivery methods out of the box:
|
|
16
16
|
* Twilio (SMS)
|
17
17
|
* Vonage / Nexmo (SMS)
|
18
18
|
* iOS Apple Push Notifications
|
19
|
+
* Firebase Cloud Messaging (Android and more)
|
19
20
|
|
20
21
|
And you can easily add new notification types for any other delivery methods.
|
21
22
|
|
@@ -190,6 +191,31 @@ Example:
|
|
190
191
|
deliver_by :slack, debug: true
|
191
192
|
```
|
192
193
|
|
194
|
+
## ✅ Best Practices
|
195
|
+
|
196
|
+
A common use case is to trigger a notification when a record is created. For example,
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
class Message < ApplicationRecord
|
200
|
+
belongs_to :recipient, class_name: "User"
|
201
|
+
|
202
|
+
after_create_commit :notify_recipient
|
203
|
+
|
204
|
+
private
|
205
|
+
|
206
|
+
def notify_recipient
|
207
|
+
NewMessageNotification.with(message: self).deliver_later(recipient)
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
If you are creating the notification on a background job (i.e. via `#deliver_later`), make sure you use a `commit` hook such as `after_create_commit` or `after_commit`.
|
212
|
+
|
213
|
+
Using `after_create` might cause the notification delivery methods to fail. This is because the job was enqueued while inside a database transaction, and the `Message` record might not yet be saved to the database.
|
214
|
+
|
215
|
+
A common symptom of this problem is undelivered notifications and the following error in your logs.
|
216
|
+
|
217
|
+
> `Discarded Noticed::DeliveryMethods::Email due to a ActiveJob::DeserializationError.`
|
218
|
+
|
193
219
|
## 🚛 Delivery Methods
|
194
220
|
|
195
221
|
The delivery methods are designed to be modular so you can customize the way each type gets delivered.
|
@@ -205,6 +231,7 @@ For example, emails will require a subject, body, and email address while an SMS
|
|
205
231
|
* [Test](docs/delivery_methods/test.md)
|
206
232
|
* [Twilio](docs/delivery_methods/twilio.md)
|
207
233
|
* [Vonage](docs/delivery_methods/vonage.md)
|
234
|
+
* [Firebase Cloud Messaging](docs/delivery_methods/fcm.md)
|
208
235
|
|
209
236
|
### Fallback Notifications
|
210
237
|
|
@@ -29,8 +29,8 @@ module Noticed
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
33
|
-
@notification = args
|
32
|
+
def assign_args(args)
|
33
|
+
@notification = args.fetch(:notification_class).constantize.new(args[:params])
|
34
34
|
@options = args[:options] || {}
|
35
35
|
@params = args[:params]
|
36
36
|
@recipient = args[:recipient]
|
@@ -39,6 +39,11 @@ module Noticed
|
|
39
39
|
# Make notification aware of database record and recipient during delivery
|
40
40
|
@notification.record = args[:record]
|
41
41
|
@notification.recipient = args[:recipient]
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def perform(args)
|
46
|
+
assign_args(args)
|
42
47
|
|
43
48
|
return if (condition = @options[:if]) && !@notification.send(condition)
|
44
49
|
return if (condition = @options[:unless]) && @notification.send(condition)
|
@@ -57,16 +62,16 @@ module Noticed
|
|
57
62
|
# Helper method for making POST requests from delivery methods
|
58
63
|
#
|
59
64
|
# Usage:
|
60
|
-
# post("http://example.com", basic_auth: {user:, pass:}, json: {}, form: {})
|
65
|
+
# post("http://example.com", basic_auth: {user:, pass:}, headers: {}, json: {}, form: {})
|
61
66
|
#
|
62
67
|
def post(url, args = {})
|
68
|
+
options ||= {}
|
63
69
|
basic_auth = args.delete(:basic_auth)
|
70
|
+
headers = args.delete(:headers)
|
64
71
|
|
65
|
-
request =
|
66
|
-
|
67
|
-
|
68
|
-
HTTP
|
69
|
-
end
|
72
|
+
request = HTTP
|
73
|
+
request = request.basic_auth(user: basic_auth[:user], pass: basic_auth[:pass]) if basic_auth
|
74
|
+
request = request.headers(headers) if headers
|
70
75
|
|
71
76
|
response = request.post(url, args)
|
72
77
|
|
@@ -76,6 +81,8 @@ module Noticed
|
|
76
81
|
end
|
77
82
|
|
78
83
|
if !options[:ignore_failure] && !response.status.success?
|
84
|
+
puts response.status
|
85
|
+
puts response.body
|
79
86
|
raise ResponseUnsuccessful.new(response)
|
80
87
|
end
|
81
88
|
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "googleauth"
|
2
|
+
|
3
|
+
# class CommentNotifier
|
4
|
+
# deliver_by :fcm, credentials: Rails.root.join("config/certs/fcm.json"), format: :format_notification
|
5
|
+
#
|
6
|
+
# deliver_by :fcm, credentials: :fcm_credentials
|
7
|
+
# def fcm_credentials
|
8
|
+
# { project_id: "api-12345" }
|
9
|
+
# end
|
10
|
+
# end
|
11
|
+
|
12
|
+
module Noticed
|
13
|
+
module DeliveryMethods
|
14
|
+
class Fcm < Base
|
15
|
+
BASE_URI = "https://fcm.googleapis.com/v1/projects/"
|
16
|
+
|
17
|
+
option :format
|
18
|
+
|
19
|
+
def deliver
|
20
|
+
device_tokens.each do |device_token|
|
21
|
+
post("#{BASE_URI}#{project_id}/messages:send", headers: {authorization: "Bearer #{access_token}"}, json: {message: format(device_token)})
|
22
|
+
rescue ResponseUnsuccessful
|
23
|
+
cleanup_invalid_token(device_token)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def cleanup_invalid_token(device_token)
|
28
|
+
return unless notification.respond_to?(:cleanup_device_token)
|
29
|
+
notification.send(:cleanup_device_token, token: device_token, platform: "fcm")
|
30
|
+
end
|
31
|
+
|
32
|
+
def credentials
|
33
|
+
@credentials ||= begin
|
34
|
+
option = options[:credentials]
|
35
|
+
credentials_hash = case option
|
36
|
+
when Hash
|
37
|
+
option
|
38
|
+
when Pathname
|
39
|
+
load_json(option)
|
40
|
+
when String
|
41
|
+
load_json(Rails.root.join(option))
|
42
|
+
when Symbol
|
43
|
+
notification.send(option)
|
44
|
+
else
|
45
|
+
Rails.application.credentials.fcm
|
46
|
+
end
|
47
|
+
|
48
|
+
credentials_hash.symbolize_keys
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def load_json(path)
|
53
|
+
JSON.parse(File.read(path))
|
54
|
+
end
|
55
|
+
|
56
|
+
def project_id
|
57
|
+
credentials[:project_id]
|
58
|
+
end
|
59
|
+
|
60
|
+
def access_token
|
61
|
+
token = authorizer.fetch_access_token!
|
62
|
+
token["access_token"]
|
63
|
+
end
|
64
|
+
|
65
|
+
def authorizer
|
66
|
+
@authorizer ||= options.fetch(:authorizer, Google::Auth::ServiceAccountCredentials).make_creds(
|
67
|
+
json_key_io: StringIO.new(credentials.to_json),
|
68
|
+
scope: "https://www.googleapis.com/auth/firebase.messaging"
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
def format(device_token)
|
73
|
+
notification.send(options[:format], device_token)
|
74
|
+
end
|
75
|
+
|
76
|
+
def device_tokens
|
77
|
+
if notification.respond_to?(:fcm_device_tokens)
|
78
|
+
Array.wrap(notification.fcm_device_tokens(recipient))
|
79
|
+
else
|
80
|
+
raise NoMethodError, <<~MESSAGE
|
81
|
+
You must implement `fcm_device_tokens` to send Firebase Cloud Messaging notifications
|
82
|
+
|
83
|
+
# This must return an Array of FCM device tokens
|
84
|
+
def fcm_device_tokens(recipient)
|
85
|
+
recipient.fcm_device_tokens.pluck(:token)
|
86
|
+
end
|
87
|
+
MESSAGE
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -51,8 +51,8 @@ module Noticed
|
|
51
51
|
You must implement `ios_device_tokens` to send iOS notifications
|
52
52
|
|
53
53
|
# This must return an Array of iOS device tokens
|
54
|
-
def ios_device_tokens(
|
55
|
-
|
54
|
+
def ios_device_tokens(recipient)
|
55
|
+
recipient.ios_device_tokens.pluck(:token)
|
56
56
|
end
|
57
57
|
MESSAGE
|
58
58
|
end
|
data/lib/noticed/version.rb
CHANGED
data/lib/noticed.rb
CHANGED
@@ -22,6 +22,7 @@ module Noticed
|
|
22
22
|
autoload :Test, "noticed/delivery_methods/test"
|
23
23
|
autoload :Twilio, "noticed/delivery_methods/twilio"
|
24
24
|
autoload :Vonage, "noticed/delivery_methods/vonage"
|
25
|
+
autoload :Fcm, "noticed/delivery_methods/fcm"
|
25
26
|
end
|
26
27
|
|
27
28
|
def self.notify(recipients:, notification:)
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# The following implements polyfills for Rails < 6.0
|
2
2
|
module ActionCable
|
3
3
|
# If the Rails 6.0 ActionCable::TestHelper is missing then allow it to autoload
|
4
|
-
unless ActionCable.const_defined?
|
4
|
+
unless ActionCable.const_defined? :TestHelper
|
5
5
|
autoload :TestHelper, "rails_6_polyfills/actioncable/test_helper.rb"
|
6
6
|
end
|
7
7
|
# If the Rails 6.0 test SubscriptionAdapter is missing then allow it to autoload
|
8
|
-
unless ActionCable.const_defined?
|
8
|
+
unless ActionCable::SubscriptionAdapter.const_defined? :Test
|
9
9
|
module SubscriptionAdapter
|
10
10
|
autoload :Test, "rails_6_polyfills/actioncable/test_adapter.rb"
|
11
11
|
end
|
@@ -13,6 +13,6 @@ module ActionCable
|
|
13
13
|
end
|
14
14
|
|
15
15
|
# If the Rails 6.0 ActionJob Serializers are missing then load support for them
|
16
|
-
unless
|
16
|
+
unless ActiveJob.const_defined?(:Serializers)
|
17
17
|
require "rails_6_polyfills/activejob/serializers"
|
18
18
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: noticed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Oliver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -132,6 +132,7 @@ files:
|
|
132
132
|
- lib/noticed/delivery_methods/base.rb
|
133
133
|
- lib/noticed/delivery_methods/database.rb
|
134
134
|
- lib/noticed/delivery_methods/email.rb
|
135
|
+
- lib/noticed/delivery_methods/fcm.rb
|
135
136
|
- lib/noticed/delivery_methods/ios.rb
|
136
137
|
- lib/noticed/delivery_methods/microsoft_teams.rb
|
137
138
|
- lib/noticed/delivery_methods/slack.rb
|
@@ -169,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
169
170
|
- !ruby/object:Gem::Version
|
170
171
|
version: '0'
|
171
172
|
requirements: []
|
172
|
-
rubygems_version: 3.2.
|
173
|
+
rubygems_version: 3.2.32
|
173
174
|
signing_key:
|
174
175
|
specification_version: 4
|
175
176
|
summary: Notifications for Ruby on Rails applications
|