noticed 2.0.3 → 2.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +137 -14
- data/app/channels/noticed/notification_channel.rb +1 -1
- data/app/models/concerns/noticed/deliverable.rb +2 -2
- data/lib/generators/noticed/delivery_method_generator.rb +1 -0
- data/lib/generators/noticed/notifier_generator.rb +1 -0
- data/lib/generators/noticed/templates/application_delivery_method.rb.tt +2 -0
- data/lib/generators/noticed/templates/application_notifier.rb.tt +2 -0
- data/lib/generators/noticed/templates/delivery_method.rb.tt +1 -1
- data/lib/generators/noticed/templates/notifier.rb.tt +1 -1
- data/lib/noticed/delivery_method.rb +7 -2
- data/lib/noticed/delivery_methods/fcm.rb +10 -1
- data/lib/noticed/delivery_methods/ios.rb +4 -3
- data/lib/noticed/version.rb +1 -1
- data/lib/noticed.rb +3 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af64af61a772e3e67456ecab3807b7ad1c9c689a8b411d45583f1c68f61ebc4e
|
4
|
+
data.tar.gz: eed9bec207e731b07727e7a85d500e90d7f9db6437cdfadc6ac0b39153a2bb11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c442042bac58a37b9f3adca3b534c20839f662ce9c7d3336691425e0363990686bbfefbc42cfbf581593d11b2fc24ebea99c6b925bafde71934ba9d9ef580a8a
|
7
|
+
data.tar.gz: 26215e49a2786596852dcf539dab854a5e8550eb83c1240acfe872aa64a163227237ca212d6e9f936d537768df6117793fa2b9f1234cd525083393604860bf2b
|
data/README.md
CHANGED
@@ -62,13 +62,13 @@ rails db:migrate
|
|
62
62
|
|
63
63
|
Noticed operates with a few constructs: Notifiers, delivery methods, and Notification records.
|
64
64
|
|
65
|
-
To start, generate a Notifier:
|
65
|
+
To start, generate a Notifier:
|
66
66
|
|
67
67
|
```sh
|
68
68
|
rails generate noticed:notifier NewCommentNotifier
|
69
69
|
```
|
70
70
|
|
71
|
-
|
71
|
+
### Notifier Objects
|
72
72
|
|
73
73
|
Notifiers are essentially the controllers of the Noticed ecosystem and represent an Event. As such, we recommend naming them with the event they model in mind — be it a `NewSaleNotifier,` `ChargeFailureNotifier`, etc.
|
74
74
|
|
@@ -117,7 +117,75 @@ end
|
|
117
117
|
|
118
118
|
For deeper specifics on setting up the `:action_cable`, `:email`, and `:discord` (bulk) delivery methods, refer to their docs: [`action_cable`](docs/delivery_methods/action_cable.md), [`email`](docs/delivery_methods/email.md), and [`discord` (bulk)](docs/bulk_delivery_methods/discord.md).
|
119
119
|
|
120
|
-
|
120
|
+
#### Delivery Method Configuration
|
121
|
+
|
122
|
+
Each delivery method can be configured with a block that yields a `config` object.
|
123
|
+
|
124
|
+
Procs/Lambdas will be evaluated when needed and symbols can be used to call a method.
|
125
|
+
|
126
|
+
If you are using a symbol to call a method, we pass the notification object as an argument to the method. This allows you to access the notification object within the method.
|
127
|
+
Your method must accept a single argument. If you don't need to use the object you can just use `(*)`.
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
class CommentNotifier < Noticed::Event
|
131
|
+
deliver_by :ios do |config|
|
132
|
+
config.format = :ios_format
|
133
|
+
config.apns_key = :ios_cert
|
134
|
+
config.key_id = :ios_key_id
|
135
|
+
config.team_id = :ios_team_id
|
136
|
+
config.bundle_identifier = Rails.application.credentials.dig(:ios, :bundle_identifier)
|
137
|
+
config.device_tokens = :ios_device_tokens
|
138
|
+
config.if = ->(notification) { recipient.send_ios_notification? }
|
139
|
+
end
|
140
|
+
|
141
|
+
def ios_format(apn)
|
142
|
+
apn.alert = { title:, body: }
|
143
|
+
apn.mutable_content = true
|
144
|
+
apn.content_available = true
|
145
|
+
apn.sound = "notification.m4r"
|
146
|
+
apn.custom_payload = {
|
147
|
+
url:,
|
148
|
+
type: self.class.name,
|
149
|
+
id: record.id,
|
150
|
+
image_url: "" || image_url,
|
151
|
+
params: params.to_json
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
def ios_cert(*)
|
156
|
+
Rails.application.credentials.dig(:ios, Rails.env.to_sym, :apns_token_cert)
|
157
|
+
end
|
158
|
+
|
159
|
+
def ios_key_id(*)
|
160
|
+
Rails.application.credentials.dig(:ios, Rails.env.to_sym, :key_id)
|
161
|
+
end
|
162
|
+
|
163
|
+
def ios_team_id(*)
|
164
|
+
Rails.application.credentials.dig(:ios, Rails.env.to_sym, :team_id)
|
165
|
+
end
|
166
|
+
|
167
|
+
def ios_bundle_id(*)
|
168
|
+
Rails.application.credentials.dig(:ios, Rails.env.to_sym, :bundle_identifier)
|
169
|
+
end
|
170
|
+
|
171
|
+
def ios_device_tokens(notification)
|
172
|
+
notification.recipient.ios_device_tokens
|
173
|
+
end
|
174
|
+
|
175
|
+
def send_ios_notification?(notification)
|
176
|
+
recipient = notification.recipient
|
177
|
+
return false unless recipient.is_a?(User)
|
178
|
+
|
179
|
+
recipient.send_notifications?
|
180
|
+
end
|
181
|
+
|
182
|
+
def url
|
183
|
+
comment_thread_path(record.thread)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
#### Required Params
|
121
189
|
|
122
190
|
While explicit / required parameters are completely optional, Notifiers are able to opt in to required parameters via the `required_params` method:
|
123
191
|
|
@@ -126,7 +194,10 @@ class CarSaleNotifier < Noticed::Event
|
|
126
194
|
deliver_by :email { |c| c.mailer = "BranchMailer" }
|
127
195
|
|
128
196
|
# `record` is the Car record, `Branch` is the dealership
|
129
|
-
required_params :
|
197
|
+
required_params :branch
|
198
|
+
|
199
|
+
# To validate the `:record` param, add a validation since it is an association on the Noticed::Event
|
200
|
+
validates :record, presence: true
|
130
201
|
end
|
131
202
|
```
|
132
203
|
|
@@ -141,8 +212,7 @@ CarSaleNotifier.with(record: Car.last, branch: Branch.last).deliver(Branch.hq)
|
|
141
212
|
```
|
142
213
|
|
143
214
|
|
144
|
-
|
145
|
-
##### Helper Methods
|
215
|
+
#### Helper Methods
|
146
216
|
|
147
217
|
Notifiers can implement various helper methods, within a `notification_methods` block, that make it easier to render the resulting notification directly. These helpers can be helpful depending on where and how you choose to render notifications. A common use is rendering a user’s notifications in your web UI as standard ERB. These notification helper methods make that rendering much simpler:
|
148
218
|
|
@@ -156,7 +226,7 @@ Notifiers can implement various helper methods, within a `notification_methods`
|
|
156
226
|
|
157
227
|
On the other hand, if you’re using email delivery, ActionMailer has its own full stack for setting up objects and rendering. Your notification helper methods will always be available from the notification object, but using ActionMailer’s own paradigms may fit better for that particular delivery method. YMMV.
|
158
228
|
|
159
|
-
|
229
|
+
#### URL Helpers
|
160
230
|
|
161
231
|
Rails url helpers are included in Notifiers by default so you have full access to them in your notification helper methods, just like you would in your controllers and views.
|
162
232
|
|
@@ -166,7 +236,7 @@ _But don't forget_, you'll need to configure `default_url_options` in order for
|
|
166
236
|
Rails.application.routes.default_url_options[:host] = 'localhost:3000'
|
167
237
|
```
|
168
238
|
|
169
|
-
|
239
|
+
#### Translations
|
170
240
|
|
171
241
|
We've also included Rails’ `translate` and `t` helpers for you to use in your notification helper methods. This also provides an easy way of scoping translations. If the key starts with a period, it will automatically scope the key under `notifiers`, the underscored name of the notifier class, and `notification`. For example:
|
172
242
|
|
@@ -175,13 +245,13 @@ From the above Notifier...
|
|
175
245
|
```ruby
|
176
246
|
class NewCommentNotifier < Noticed::Event
|
177
247
|
# ...
|
178
|
-
|
248
|
+
|
179
249
|
notification_methods do
|
180
250
|
def message
|
181
251
|
t(".message")
|
182
252
|
end
|
183
253
|
end
|
184
|
-
|
254
|
+
|
185
255
|
# ...
|
186
256
|
end
|
187
257
|
```
|
@@ -206,7 +276,7 @@ en:
|
|
206
276
|
|
207
277
|
Or, if you have your Notifier within another module, such as `Admin::NewCommentNotifier`, the resulting lookup path will be `en.notifiers.admin.new_comment_notifier.notification.message` (modules become nesting steps).
|
208
278
|
|
209
|
-
|
279
|
+
#### Tip: Capture User Preferences
|
210
280
|
|
211
281
|
You can use the `if:` and `unless: ` options on your delivery methods to check the user's preferences and skip processing if they have disabled that type of notification.
|
212
282
|
|
@@ -221,8 +291,42 @@ class CommentNotifier < Noticed::Event
|
|
221
291
|
end
|
222
292
|
end
|
223
293
|
```
|
294
|
+
#### Tip: Extracting Delivery Method Configurations
|
295
|
+
|
296
|
+
If you want to reuse delivery method configurations across multiple Notifiers, you can extract them into a module and include them in your Notifiers.
|
297
|
+
|
298
|
+
```ruby
|
299
|
+
# /app/notifiers/notifiers/comment_notifier.rb
|
300
|
+
class CommentNotifier < Noticed::Event
|
301
|
+
include IosNotifier
|
302
|
+
include AndriodNotifer
|
303
|
+
include EmailNotifier
|
304
|
+
|
305
|
+
validates :record, presence: true
|
306
|
+
end
|
307
|
+
|
308
|
+
# /app/notifiers/concerns/ios_notifier.rb
|
309
|
+
module IosNotifier
|
310
|
+
extend ActiveSupport::Concern
|
311
|
+
|
312
|
+
included do
|
313
|
+
deliver_by :ios do |config|
|
314
|
+
config.device_tokens = ->(recipient) { recipient.notification_tokens.where(platform: :iOS).pluck(:token) }
|
315
|
+
config.format = ->(apn) {
|
316
|
+
apn.alert = "Hello world"
|
317
|
+
apn.custom_payload = {url: root_url(host: "example.org")}
|
318
|
+
}
|
319
|
+
config.bundle_identifier = Rails.application.credentials.dig(:ios, :bundle_id)
|
320
|
+
config.key_id = Rails.application.credentials.dig(:ios, :key_id)
|
321
|
+
config.team_id = Rails.application.credentials.dig(:ios, :team_id)
|
322
|
+
config.apns_key = Rails.application.credentials.dig(:ios, :apns_key)
|
323
|
+
config.if = ->(recipient) { recipient.ios_notifications? }
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
```
|
224
328
|
|
225
|
-
|
329
|
+
#### Shared Delivery Method Options
|
226
330
|
|
227
331
|
Each of these options are available for every delivery method (individual or bulk). The value passed may be a lambda, a symbol that represents a callable method, a symbol value, or a string value.
|
228
332
|
|
@@ -232,7 +336,7 @@ Each of these options are available for every delivery method (individual or bul
|
|
232
336
|
* `config.wait_until` — (Should yield a specific time object) Delays the job that runs this delivery method until the specific time specified
|
233
337
|
* `config.queue` — Sets the ActiveJob queue name to be used for the job that runs this delivery method
|
234
338
|
|
235
|
-
|
339
|
+
### Sending Notifications
|
236
340
|
|
237
341
|
Following the `NewCommentNotifier` example above, here’s how we might invoke the Notifier to send notifications to every author in the thread about a new comment being added:
|
238
342
|
|
@@ -400,6 +504,18 @@ class DeliveryMethods::WhatsApp < Noticed::DeliveryMethod
|
|
400
504
|
end
|
401
505
|
```
|
402
506
|
|
507
|
+
#### Callbacks
|
508
|
+
|
509
|
+
Callbacks for delivery methods wrap the _actual_ delivery of the notification. You can use `before_deliver`, `around_deliver` and `after_deliver` in your custom delivery methods.
|
510
|
+
|
511
|
+
```ruby
|
512
|
+
class DeliveryMethods::Discord < Noticed::DeliveryMethod
|
513
|
+
after_deliver do
|
514
|
+
# Do whatever you want
|
515
|
+
end
|
516
|
+
end
|
517
|
+
```
|
518
|
+
|
403
519
|
### 📦 Database Model
|
404
520
|
|
405
521
|
The Noticed database models include several helpful features to make working with notifications easier.
|
@@ -484,6 +600,14 @@ end
|
|
484
600
|
# @post.noticed_events.each { |ne| ne.notifications... }
|
485
601
|
```
|
486
602
|
|
603
|
+
#### ActiveJob Parent Class
|
604
|
+
|
605
|
+
Noticed uses its own `Noticed::ApplicationJob` as the base job for all notifications. In the event that you would like to customize the parent job class, there is a `parent_class` attribute that can be overridden with your own class. This should be done in a `noticed.rb` initializer.
|
606
|
+
|
607
|
+
```ruby
|
608
|
+
Noticed.parent_class = "ApplicationJob"
|
609
|
+
```
|
610
|
+
|
487
611
|
#### Handling Deleted Records
|
488
612
|
|
489
613
|
Generally we recommend using a `dependent: ___` relationship on your models to avoid cases where Noticed Events or Notifications are left lingering when your models are destroyed. In the case that they are or data becomes mis-matched, you’ll likely run into deserialization issues. That may be globally alleviated with the following snippet, but use with caution.
|
@@ -508,4 +632,3 @@ DATABASE_URL=postgres://127.0.0.1/noticed_test rails test
|
|
508
632
|
|
509
633
|
## 📝 License
|
510
634
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
511
|
-
|
@@ -91,7 +91,7 @@ module Noticed
|
|
91
91
|
def recipient_attributes_for(recipient)
|
92
92
|
{
|
93
93
|
type: "#{self.class.name}::Notification",
|
94
|
-
recipient_type: recipient.class.name,
|
94
|
+
recipient_type: recipient.class.base_class.name,
|
95
95
|
recipient_id: recipient.id
|
96
96
|
}
|
97
97
|
end
|
@@ -103,7 +103,7 @@ module Noticed
|
|
103
103
|
|
104
104
|
def validate_params!
|
105
105
|
required_param_names.each do |param_name|
|
106
|
-
raise ValidationError, "Param `#{param_name}` is required for #{self.class.name}." unless params
|
106
|
+
raise ValidationError, "Param `#{param_name}` is required for #{self.class.name}." unless params.has_key?(param_name)
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
@@ -12,6 +12,7 @@ module Noticed
|
|
12
12
|
desc "Generates a class for a custom delivery method with the given NAME."
|
13
13
|
|
14
14
|
def generate_notification
|
15
|
+
template "application_delivery_method.rb", "app/notifiers/application_delivery_method.rb"
|
15
16
|
template "delivery_method.rb", "app/notifiers/delivery_methods/#{singular_name}.rb"
|
16
17
|
end
|
17
18
|
end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
module Noticed
|
2
|
-
class DeliveryMethod <
|
2
|
+
class DeliveryMethod < Noticed.parent_class.constantize
|
3
3
|
include ApiClient
|
4
4
|
include RequiredOptions
|
5
5
|
|
6
|
+
extend ActiveModel::Callbacks
|
7
|
+
define_model_callbacks :deliver
|
8
|
+
|
6
9
|
class_attribute :logger, default: Rails.logger
|
7
10
|
|
8
11
|
attr_reader :config, :event, :notification
|
@@ -19,7 +22,9 @@ module Noticed
|
|
19
22
|
return false if config.has_key?(:if) && !evaluate_option(:if)
|
20
23
|
return false if config.has_key?(:unless) && evaluate_option(:unless)
|
21
24
|
|
22
|
-
deliver
|
25
|
+
run_callbacks :deliver do
|
26
|
+
deliver
|
27
|
+
end
|
23
28
|
end
|
24
29
|
|
25
30
|
def deliver
|
@@ -14,7 +14,7 @@ module Noticed
|
|
14
14
|
def send_notification(device_token)
|
15
15
|
post_request("https://fcm.googleapis.com/v1/projects/#{credentials[:project_id]}/messages:send",
|
16
16
|
headers: {authorization: "Bearer #{access_token}"},
|
17
|
-
json:
|
17
|
+
json: format_notification(device_token))
|
18
18
|
rescue Noticed::ResponseUnsuccessful => exception
|
19
19
|
if exception.response.code == "404" && config[:invalid_token]
|
20
20
|
notification.instance_exec(device_token, &config[:invalid_token])
|
@@ -23,6 +23,15 @@ module Noticed
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
def format_notification(device_token)
|
27
|
+
method = config[:json]
|
28
|
+
if method.is_a?(Symbol) && event.respond_to?(method)
|
29
|
+
event.send(method, device_token)
|
30
|
+
else
|
31
|
+
notification.instance_exec(device_token, &method)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
26
35
|
def credentials
|
27
36
|
@credentials ||= begin
|
28
37
|
value = evaluate_option(:credentials)
|
@@ -33,6 +33,7 @@ module Noticed
|
|
33
33
|
apn.topic = evaluate_option(:bundle_identifier)
|
34
34
|
|
35
35
|
if (method = config[:format])
|
36
|
+
method = event.send(method, apn) if method.is_a?(Symbol) && event.respond_to?(method)
|
36
37
|
notification.instance_exec(apn, &method)
|
37
38
|
elsif notification.params.try(:has_key?, :message)
|
38
39
|
apn.alert = notification.params[:message]
|
@@ -70,9 +71,9 @@ module Noticed
|
|
70
71
|
def connection_pool_options
|
71
72
|
{
|
72
73
|
auth_method: :token,
|
73
|
-
cert_path: StringIO.new(
|
74
|
-
key_id:
|
75
|
-
team_id:
|
74
|
+
cert_path: StringIO.new(evaluate_option(:apns_key)),
|
75
|
+
key_id: evaluate_option(:key_id),
|
76
|
+
team_id: evaluate_option(:team_id)
|
76
77
|
}
|
77
78
|
end
|
78
79
|
|
data/lib/noticed/version.rb
CHANGED
data/lib/noticed.rb
CHANGED
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: 2.0.
|
4
|
+
version: 2.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Oliver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-01-
|
11
|
+
date: 2024-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -50,6 +50,8 @@ files:
|
|
50
50
|
- lib/generators/noticed/install_generator.rb
|
51
51
|
- lib/generators/noticed/notifier_generator.rb
|
52
52
|
- lib/generators/noticed/templates/README
|
53
|
+
- lib/generators/noticed/templates/application_delivery_method.rb.tt
|
54
|
+
- lib/generators/noticed/templates/application_notifier.rb.tt
|
53
55
|
- lib/generators/noticed/templates/delivery_method.rb.tt
|
54
56
|
- lib/generators/noticed/templates/notifier.rb.tt
|
55
57
|
- lib/noticed.rb
|