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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90b43c50384068092455c10cd6686fc46cd766121c0ea5cf593bbc4c8306e8de
4
- data.tar.gz: 23edb385b0c9981dd9c292c8f4c15ce6fadd9abb131adc1eb6440ab39c5fa186
3
+ metadata.gz: 85a89c655531764a6b6c97213a6b1368c21bee48e55298cb35be1154c32534ff
4
+ data.tar.gz: 404987e57e6f834fe21dc9b895664643767ed08e0d23e05c32cb31ebe0a8c5ab
5
5
  SHA512:
6
- metadata.gz: 9a5d92df6618d53f8be91ca71bdf6dfc6ff0b66279662a5690c6efaa162939f2ae4fe1868956427ff10a83fa77329c16c96af3faef9e2fa48e441f1478c91ed0
7
- data.tar.gz: 6d485a661fe14b24811479615e125cb4bf2794808dd28b39c102e677b1a1e99a0f22807acbc75a728442764f521c498ffa884998e243dacad5ea9e4e4cd2ca19
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 perform(args)
33
- @notification = args[:notification_class].constantize.new(args[:params])
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 = if basic_auth
66
- HTTP.basic_auth(user: basic_auth[:user], pass: basic_auth[:pass])
67
- else
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(user)
55
- user.ios_device_tokens.pluck(:token)
54
+ def ios_device_tokens(recipient)
55
+ recipient.ios_device_tokens.pluck(:token)
56
56
  end
57
57
  MESSAGE
58
58
  end
@@ -1,3 +1,3 @@
1
1
  module Noticed
2
- VERSION = "1.5.5"
2
+ VERSION = "1.5.6"
3
3
  end
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? "TestHelper"
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? "SubscriptionAdapter::Test"
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 Object.const_defined?("ActiveJob::Serializers")
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.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: 2021-12-01 00:00:00.000000000 Z
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.22
173
+ rubygems_version: 3.2.32
173
174
  signing_key:
174
175
  specification_version: 4
175
176
  summary: Notifications for Ruby on Rails applications