noticed 1.3.2 → 1.6.3
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 +76 -177
- data/lib/generators/noticed/model/base_generator.rb +47 -0
- data/lib/generators/noticed/model/mysql_generator.rb +18 -0
- data/lib/generators/noticed/model/postgresql_generator.rb +18 -0
- data/lib/generators/noticed/model/sqlite3_generator.rb +18 -0
- data/lib/generators/noticed/model_generator.rb +10 -2
- data/lib/generators/noticed/templates/README +1 -1
- data/lib/noticed/base.rb +23 -7
- data/lib/noticed/coder.rb +2 -0
- data/lib/noticed/delivery_methods/action_cable.rb +13 -1
- data/lib/noticed/delivery_methods/base.rb +22 -13
- data/lib/noticed/delivery_methods/email.rb +29 -4
- data/lib/noticed/delivery_methods/fcm.rb +96 -0
- data/lib/noticed/delivery_methods/ios.rb +171 -0
- data/lib/noticed/engine.rb +4 -0
- data/lib/noticed/has_notifications.rb +21 -4
- data/lib/noticed/model.rb +22 -2
- data/lib/noticed/translation.rb +5 -1
- data/lib/noticed/version.rb +1 -1
- data/lib/noticed.rb +4 -11
- data/lib/rails_6_polyfills/actioncable/test_adapter.rb +70 -0
- data/lib/rails_6_polyfills/actioncable/test_helper.rb +143 -0
- data/lib/rails_6_polyfills/activejob/serializers.rb +240 -0
- data/lib/rails_6_polyfills/base.rb +18 -0
- metadata +15 -75
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dca9fddb81724156c172bcb7ac9bdcbc7d3571554dd3b906d3df02395c730b23
|
|
4
|
+
data.tar.gz: 5a8676aa3224c61b6623b81db22aecde7fa175c5514da465dfd735269b91394a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 582f1a4e7282af29b7a66fcf322f13e2af6880757a3871a7cb74a44b3cc5fb9de6e404e5a62d78349cd7283caab14445bb63a508595878d98cadc352ea8bcbc1
|
|
7
|
+
data.tar.gz: 3764af8b5240a7b7de561512086497ea60ff9fecb1ff49d85ce2ea42509b97188519a97d9e05c884e0d48aebbfdca3cb27022b88347160e066942fd00b191ec5
|
data/README.md
CHANGED
|
@@ -15,6 +15,8 @@ Currently, we support these notification delivery methods out of the box:
|
|
|
15
15
|
* Microsoft Teams
|
|
16
16
|
* Twilio (SMS)
|
|
17
17
|
* Vonage / Nexmo (SMS)
|
|
18
|
+
* iOS Apple Push Notifications
|
|
19
|
+
* Firebase Cloud Messaging (Android and more)
|
|
18
20
|
|
|
19
21
|
And you can easily add new notification types for any other delivery methods.
|
|
20
22
|
|
|
@@ -104,9 +106,10 @@ end
|
|
|
104
106
|
|
|
105
107
|
**Shared Options**
|
|
106
108
|
|
|
107
|
-
* `if: :method_name` - Calls `method_name`and cancels delivery method if `false` is returned
|
|
108
|
-
* `unless: :method_name` - Calls `method_name`and cancels delivery method if `true` is returned
|
|
109
|
+
* `if: :method_name` - Calls `method_name` and cancels delivery method if `false` is returned
|
|
110
|
+
* `unless: :method_name` - Calls `method_name` and cancels delivery method if `true` is returned
|
|
109
111
|
* `delay: ActiveSupport::Duration` - Delays the delivery for the given duration of time
|
|
112
|
+
* `delay: :method_name` - Calls `method_name` which should return an `ActiveSupport::Duration` and delays the delivery for the given duration of time
|
|
110
113
|
|
|
111
114
|
##### Helper Methods
|
|
112
115
|
|
|
@@ -159,6 +162,10 @@ For example:
|
|
|
159
162
|
|
|
160
163
|
`t(".message")` looks up `en.notifications.new_comment.message`
|
|
161
164
|
|
|
165
|
+
Or when notification class is in module:
|
|
166
|
+
|
|
167
|
+
`t(".message") # in Admin::NewComment` looks up `en.notifications.admin.new_comment.message`
|
|
168
|
+
|
|
162
169
|
##### User Preferences
|
|
163
170
|
|
|
164
171
|
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.
|
|
@@ -175,184 +182,76 @@ class CommentNotification < Noticed::Base
|
|
|
175
182
|
end
|
|
176
183
|
```
|
|
177
184
|
|
|
178
|
-
##
|
|
179
|
-
|
|
180
|
-
The delivery methods are designed to be modular so you can customize the way each type gets delivered.
|
|
181
|
-
|
|
182
|
-
For example, emails will require a subject, body, and email address while an SMS requires a phone number and simple message. You can define the formats for each of these in your Notification and the delivery method will handle the processing of it.
|
|
183
|
-
|
|
184
|
-
### Database
|
|
185
|
-
|
|
186
|
-
Writes notification to the database.
|
|
187
|
-
|
|
188
|
-
`deliver_by :database`
|
|
189
|
-
|
|
190
|
-
**Note:** Database notifications are special in that they will run before the other delivery methods. We do this so you can reference the database record ID in other delivery methods. For that same reason, the delivery can't be delayed (via the `delay` option) or an error will be raised.
|
|
191
|
-
|
|
192
|
-
##### Options
|
|
193
|
-
|
|
194
|
-
* `association` - *Optional*
|
|
195
|
-
|
|
196
|
-
The name of the database association to use. Defaults to `:notifications`
|
|
197
|
-
|
|
198
|
-
* `format: :format_for_database` - *Optional*
|
|
199
|
-
|
|
200
|
-
Use a custom method to define the attributes saved to the database
|
|
201
|
-
|
|
202
|
-
### Email
|
|
203
|
-
|
|
204
|
-
Sends an email notification. Emails will always be sent with `deliver_later`
|
|
205
|
-
|
|
206
|
-
`deliver_by :email, mailer: "UserMailer"`
|
|
207
|
-
|
|
208
|
-
##### Options
|
|
209
|
-
|
|
210
|
-
* `mailer` - **Required**
|
|
211
|
-
|
|
212
|
-
The mailer that should send the email
|
|
213
|
-
|
|
214
|
-
* `method: :invoice_paid` - *Optional*
|
|
215
|
-
|
|
216
|
-
Used to customize the method on the mailer that is called
|
|
217
|
-
|
|
218
|
-
* `format: :format_for_email` - *Optional*
|
|
219
|
-
|
|
220
|
-
Use a custom method to define the params sent to the mailer. `recipient` will be merged into the params.
|
|
221
|
-
|
|
222
|
-
### ActionCable
|
|
223
|
-
|
|
224
|
-
Sends a notification to the browser via websockets (ActionCable channel by default).
|
|
225
|
-
|
|
226
|
-
`deliver_by :action_cable`
|
|
227
|
-
|
|
228
|
-
##### Options
|
|
229
|
-
|
|
230
|
-
* `format: :format_for_action_cable` - *Optional*
|
|
231
|
-
|
|
232
|
-
Use a custom method to define the Hash sent through ActionCable
|
|
233
|
-
|
|
234
|
-
* `channel` - *Optional*
|
|
235
|
-
|
|
236
|
-
Override the ActionCable channel used to send notifications.
|
|
237
|
-
|
|
238
|
-
Defaults to `Noticed::NotificationChannel`
|
|
239
|
-
|
|
240
|
-
### Slack
|
|
241
|
-
|
|
242
|
-
Sends a Slack notification via webhook.
|
|
243
|
-
|
|
244
|
-
`deliver_by :slack`
|
|
245
|
-
|
|
246
|
-
##### Options
|
|
247
|
-
|
|
248
|
-
* `format: :format_for_slack` - *Optional*
|
|
249
|
-
|
|
250
|
-
Use a custom method to define the payload sent to Slack. Method should return a Hash.
|
|
251
|
-
|
|
252
|
-
* `url: :url_for_slack` - *Optional*
|
|
253
|
-
|
|
254
|
-
Use a custom method to retrieve the Slack Webhook URL. Method should return a String.
|
|
185
|
+
## 🐞 Debugging
|
|
255
186
|
|
|
256
|
-
|
|
187
|
+
In order to figure out what's up when you run in to errors, you can set the `debug` parameter to `true` in your notification, which will give you a more detailed error message about what went wrong.
|
|
257
188
|
|
|
258
|
-
|
|
189
|
+
Example:
|
|
259
190
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
#### Options
|
|
265
|
-
|
|
266
|
-
* `format: :format_for_teams` - *Optional*
|
|
267
|
-
|
|
268
|
-
Use a custom method to define the payload sent to Microsoft Teams. Method should return a Hash.
|
|
269
|
-
Documentation for posting via Webhooks available at: https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook
|
|
270
|
-
|
|
271
|
-
```ruby
|
|
272
|
-
{
|
|
273
|
-
title: "This is the title for the card",
|
|
274
|
-
text: "This is the body text for the card",
|
|
275
|
-
sections: [{activityTitle: "Section Title", activityText: "Section Text"}],
|
|
276
|
-
"potentialAction": [{
|
|
277
|
-
"@type": "OpenUri",
|
|
278
|
-
name: "Button Text",
|
|
279
|
-
targets: [{
|
|
280
|
-
os: "default",
|
|
281
|
-
uri: "https://example.com/foo/action"
|
|
282
|
-
}]
|
|
283
|
-
}]
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
* `url: :url_for_teams_channel`: - *Optional*
|
|
289
|
-
|
|
290
|
-
Use a custom method to retrieve the MS Teams Webhook URL. Method should return a string.
|
|
291
|
-
|
|
292
|
-
Defaults to `Rails.application.credentials.microsoft_teams[:notification_url]`
|
|
293
|
-
|
|
294
|
-
### Twilio SMS
|
|
295
|
-
|
|
296
|
-
Sends an SMS notification via Twilio.
|
|
297
|
-
|
|
298
|
-
`deliver_by :twilio`
|
|
191
|
+
```ruby
|
|
192
|
+
deliver_by :slack, debug: true
|
|
193
|
+
```
|
|
299
194
|
|
|
300
|
-
|
|
195
|
+
## ✅ Best Practices
|
|
301
196
|
|
|
302
|
-
|
|
197
|
+
### Creating a notification from an Active Record callback
|
|
303
198
|
|
|
304
|
-
|
|
199
|
+
A common use case is to trigger a notification when a record is created. For example,
|
|
305
200
|
|
|
306
|
-
|
|
201
|
+
```ruby
|
|
202
|
+
class Message < ApplicationRecord
|
|
203
|
+
belongs_to :recipient, class_name: "User"
|
|
307
204
|
|
|
308
|
-
|
|
205
|
+
after_create_commit :notify_recipient
|
|
309
206
|
|
|
310
|
-
|
|
207
|
+
private
|
|
311
208
|
|
|
312
|
-
|
|
209
|
+
def notify_recipient
|
|
210
|
+
NewMessageNotification.with(message: self).deliver_later(recipient)
|
|
211
|
+
end
|
|
212
|
+
```
|
|
313
213
|
|
|
314
|
-
|
|
214
|
+
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`.
|
|
315
215
|
|
|
316
|
-
|
|
216
|
+
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.
|
|
317
217
|
|
|
318
|
-
|
|
218
|
+
A common symptom of this problem is undelivered notifications and the following error in your logs.
|
|
319
219
|
|
|
320
|
-
|
|
321
|
-
{
|
|
322
|
-
Body: notification.params[:message],
|
|
323
|
-
From: twilio_credentials[:number],
|
|
324
|
-
To: recipient.phone_number
|
|
325
|
-
}
|
|
326
|
-
```
|
|
220
|
+
> `Discarded Noticed::DeliveryMethods::Email due to a ActiveJob::DeserializationError.`
|
|
327
221
|
|
|
328
|
-
###
|
|
222
|
+
### Renaming notifications
|
|
329
223
|
|
|
330
|
-
|
|
224
|
+
If you rename the class of a notification object your existing queries can break. This is because Noticed serializes the class name and sets it to the `type` column on the `Notification` record.
|
|
331
225
|
|
|
332
|
-
`
|
|
226
|
+
You can catch these errors at runtime by using `YourNotificationClassName.name` instead of hardcoding the string when performing a query.
|
|
333
227
|
|
|
334
|
-
|
|
228
|
+
```ruby
|
|
229
|
+
Notification.where(type: YourNotificationClassName.name) # good
|
|
230
|
+
Notification.where(type: "YourNotificationClassName") # bad
|
|
231
|
+
```
|
|
335
232
|
|
|
336
|
-
|
|
233
|
+
When renaming a notification class you will need to backfill existing notifications to reference the new name.
|
|
337
234
|
|
|
338
|
-
|
|
235
|
+
```ruby
|
|
236
|
+
Notification.where(type: "OldNotificationClassName").update_all(type: NewNotificationClassName.name)
|
|
237
|
+
```
|
|
339
238
|
|
|
340
|
-
|
|
239
|
+
## 🚛 Delivery Methods
|
|
341
240
|
|
|
342
|
-
|
|
241
|
+
The delivery methods are designed to be modular so you can customize the way each type gets delivered.
|
|
343
242
|
|
|
344
|
-
|
|
243
|
+
For example, emails will require a subject, body, and email address while an SMS requires a phone number and simple message. You can define the formats for each of these in your Notification and the delivery method will handle the processing of it.
|
|
345
244
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
245
|
+
* [Database](docs/delivery_methods/database.md)
|
|
246
|
+
* [Email](docs/delivery_methods/email.md)
|
|
247
|
+
* [ActionCable](docs/delivery_methods/action_cable.md)
|
|
248
|
+
* [iOS Apple Push Notifications](docs/delivery_methods/ios.md)
|
|
249
|
+
* [Microsoft Teams](docs/delivery_methods/microsoft_teams.md)
|
|
250
|
+
* [Slack](docs/delivery_methods/slack.md)
|
|
251
|
+
* [Test](docs/delivery_methods/test.md)
|
|
252
|
+
* [Twilio](docs/delivery_methods/twilio.md)
|
|
253
|
+
* [Vonage](docs/delivery_methods/vonage.md)
|
|
254
|
+
* [Firebase Cloud Messaging](docs/delivery_methods/fcm.md)
|
|
356
255
|
|
|
357
256
|
### Fallback Notifications
|
|
358
257
|
|
|
@@ -371,16 +270,24 @@ You can also configure multiple fallback options:
|
|
|
371
270
|
|
|
372
271
|
```ruby
|
|
373
272
|
class CriticalSystemNotification < Noticed::Base
|
|
273
|
+
deliver_by :database
|
|
374
274
|
deliver_by :slack
|
|
375
|
-
deliver_by :email, mailer: 'CriticalSystemMailer', delay: 10.minutes,
|
|
376
|
-
deliver_by :twilio, delay: 20.minutes,
|
|
275
|
+
deliver_by :email, mailer: 'CriticalSystemMailer', delay: 10.minutes, if: :unread?
|
|
276
|
+
deliver_by :twilio, delay: 20.minutes, if: :unread?
|
|
377
277
|
end
|
|
378
278
|
```
|
|
379
279
|
|
|
380
|
-
In this scenario, you
|
|
280
|
+
In this scenario, you have created an escalating notification system that
|
|
281
|
+
|
|
282
|
+
- Immediately creates a record in the database (for display directly in the app)
|
|
283
|
+
- Immediately issues a ping in Slack.
|
|
284
|
+
- If the notification remains unread after 10 minutes, it emails the team.
|
|
285
|
+
- If the notification remains unread after 20 minutes, it sends an SMS to the on-call phone.
|
|
381
286
|
|
|
382
287
|
You can mix and match the options and delivery methods to suit your application specific needs.
|
|
383
288
|
|
|
289
|
+
Please note that to implement this pattern, it is essential `deliver_by :database` is one among the different delivery methods specified. Without this, a database record of the notification will not be created.
|
|
290
|
+
|
|
384
291
|
### 🚚 Custom Delivery Methods
|
|
385
292
|
|
|
386
293
|
To generate a custom delivery method, simply run
|
|
@@ -463,22 +370,6 @@ class DeliveryMethods::Discord < Noticed::DeliveryMethods::Base
|
|
|
463
370
|
end
|
|
464
371
|
```
|
|
465
372
|
|
|
466
|
-
#### Limitations
|
|
467
|
-
|
|
468
|
-
Rails 6.1+ can serialize Class and Module objects as arguments to ActiveJob. The following syntax should work for Rails 6.1+:
|
|
469
|
-
|
|
470
|
-
```ruby
|
|
471
|
-
deliver_by DeliveryMethods::Discord
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
For Rails 6.0, you must pass strings of the class names in the `deliver_by` options.
|
|
475
|
-
|
|
476
|
-
```ruby
|
|
477
|
-
deliver_by :discord, class: "DeliveryMethods::Discord"
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
We recommend the Rails 6.0 compatible options to prevent confusion.
|
|
481
|
-
|
|
482
373
|
### 📦 Database Model
|
|
483
374
|
|
|
484
375
|
The Notification database model includes several helpful features to make working with database notifications easier.
|
|
@@ -550,7 +441,7 @@ class Post < ApplicationRecord
|
|
|
550
441
|
has_noticed_notifications
|
|
551
442
|
|
|
552
443
|
# You can override the param_name, the notification model name, or disable the before_destroy callback
|
|
553
|
-
has_noticed_notifications param_name: :parent, destroy: false,
|
|
444
|
+
has_noticed_notifications param_name: :parent, destroy: false, model_name: "Notification"
|
|
554
445
|
end
|
|
555
446
|
|
|
556
447
|
# Create a CommentNotification with a post param
|
|
@@ -564,7 +455,7 @@ CommentNotification.with(parent: @post).deliver(user)
|
|
|
564
455
|
|
|
565
456
|
#### Handling Deleted Records
|
|
566
457
|
|
|
567
|
-
If you create a notification but delete the associated record and forgot `has_noticed_notifications` on the model, the jobs for sending the notification will not be able to find the record when ActiveJob deserializes. You can
|
|
458
|
+
If you create a notification but delete the associated record and forgot `has_noticed_notifications` on the model, the jobs for sending the notification will not be able to find the record when ActiveJob deserializes. You can discard the job on these errors by adding the following to `ApplicationJob`:
|
|
568
459
|
|
|
569
460
|
```ruby
|
|
570
461
|
class ApplicationJob < ActiveJob::Base
|
|
@@ -576,5 +467,13 @@ end
|
|
|
576
467
|
|
|
577
468
|
This project uses [Standard](https://github.com/testdouble/standard) for formatting Ruby code. Please make sure to run `standardrb` before submitting pull requests.
|
|
578
469
|
|
|
470
|
+
Running tests against multiple databases locally:
|
|
471
|
+
|
|
472
|
+
```
|
|
473
|
+
DATABASE_URL=sqlite3:noticed_test rails test
|
|
474
|
+
DATABASE_URL=mysql2://root:@127.0.0.1/noticed_test rails test
|
|
475
|
+
DATABASE_URL=postgres://127.0.0.1/noticed_test rails test
|
|
476
|
+
```
|
|
477
|
+
|
|
579
478
|
## 📝 License
|
|
580
479
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/named_base"
|
|
4
|
+
|
|
5
|
+
module Noticed
|
|
6
|
+
module Generators
|
|
7
|
+
module Model
|
|
8
|
+
class BaseGenerator < Rails::Generators::NamedBase
|
|
9
|
+
include Rails::Generators::ResourceHelpers
|
|
10
|
+
|
|
11
|
+
source_root File.expand_path("../templates", __FILE__)
|
|
12
|
+
|
|
13
|
+
desc "Generates a Notification model for storing notifications."
|
|
14
|
+
|
|
15
|
+
argument :name, type: :string, default: "Notification", banner: "Notification"
|
|
16
|
+
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
|
17
|
+
|
|
18
|
+
def generate_notification
|
|
19
|
+
generate :model, name, "recipient:references{polymorphic}", "type", "params:#{json_column_type}", "read_at:datetime:index", *attributes
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def add_noticed_model
|
|
23
|
+
inject_into_class model_path, class_name, " include Noticed::Model\n"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def add_not_nullable
|
|
27
|
+
migration_path = Dir.glob(Rails.root.join("db/migrate/*")).max_by { |f| File.mtime(f) }
|
|
28
|
+
|
|
29
|
+
# Force is required because null: false already exists in the file and Thor isn't smart enough to tell the difference
|
|
30
|
+
insert_into_file migration_path, after: "t.string :type", force: true do
|
|
31
|
+
", null: false"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def done
|
|
36
|
+
readme "README" if behavior == :invoke
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def model_path
|
|
42
|
+
@model_path ||= File.join("app", "models", "#{file_path}.rb")
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/named_base"
|
|
4
|
+
require_relative "base_generator"
|
|
5
|
+
|
|
6
|
+
module Noticed
|
|
7
|
+
module Generators
|
|
8
|
+
module Model
|
|
9
|
+
class MysqlGenerator < BaseGenerator
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def json_column_type
|
|
13
|
+
"json"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/named_base"
|
|
4
|
+
require_relative "base_generator"
|
|
5
|
+
|
|
6
|
+
module Noticed
|
|
7
|
+
module Generators
|
|
8
|
+
module Model
|
|
9
|
+
class PostgresqlGenerator < BaseGenerator
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def json_column_type
|
|
13
|
+
"jsonb"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/named_base"
|
|
4
|
+
require_relative "base_generator"
|
|
5
|
+
|
|
6
|
+
module Noticed
|
|
7
|
+
module Generators
|
|
8
|
+
module Model
|
|
9
|
+
class Sqlite3Generator < BaseGenerator
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def json_column_type
|
|
13
|
+
"json"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -42,14 +42,22 @@ module Noticed
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def params_column
|
|
45
|
-
case
|
|
46
|
-
when "postgresql"
|
|
45
|
+
case current_adapter
|
|
46
|
+
when "postgresql", "postgis"
|
|
47
47
|
"params:jsonb"
|
|
48
48
|
else
|
|
49
49
|
# MySQL and SQLite both support json
|
|
50
50
|
"params:json"
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
|
+
|
|
54
|
+
def current_adapter
|
|
55
|
+
if ActiveRecord::Base.respond_to?(:connection_db_config)
|
|
56
|
+
ActiveRecord::Base.connection_db_config.adapter
|
|
57
|
+
else
|
|
58
|
+
ActiveRecord::Base.connection_config[:adapter]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
53
61
|
end
|
|
54
62
|
end
|
|
55
63
|
end
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
|
|
4
4
|
Next steps:
|
|
5
5
|
1. Run "rails db:migrate"
|
|
6
|
-
2. Add "has_many :notifications, as: :recipient" to your User model(s).
|
|
6
|
+
2. Add "has_many :notifications, as: :recipient, dependent: :destroy" to your User model(s).
|
|
7
7
|
3. Generate notifications with "rails g noticed:notification"
|
data/lib/noticed/base.rb
CHANGED
|
@@ -9,7 +9,7 @@ module Noticed
|
|
|
9
9
|
class_attribute :delivery_methods, instance_writer: false, default: []
|
|
10
10
|
class_attribute :param_names, instance_writer: false, default: []
|
|
11
11
|
|
|
12
|
-
# Gives notifications access to the record and recipient
|
|
12
|
+
# Gives notifications access to the record and recipient during delivery
|
|
13
13
|
attr_accessor :record, :recipient
|
|
14
14
|
|
|
15
15
|
delegate :read?, :unread?, to: :record
|
|
@@ -21,7 +21,7 @@ module Noticed
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
# Copy delivery methods from parent
|
|
24
|
-
def inherited(base)
|
|
24
|
+
def inherited(base) # :nodoc:
|
|
25
25
|
base.delivery_methods = delivery_methods.dup
|
|
26
26
|
base.param_names = param_names.dup
|
|
27
27
|
super
|
|
@@ -31,6 +31,16 @@ module Noticed
|
|
|
31
31
|
new(params)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
# Shortcut for delivering without params
|
|
35
|
+
def deliver(recipients)
|
|
36
|
+
new.deliver(recipients)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Shortcut for delivering later without params
|
|
40
|
+
def deliver_later(recipients)
|
|
41
|
+
new.deliver_later(recipients)
|
|
42
|
+
end
|
|
43
|
+
|
|
34
44
|
def params(*names)
|
|
35
45
|
param_names.concat Array.wrap(names)
|
|
36
46
|
end
|
|
@@ -65,28 +75,31 @@ module Noticed
|
|
|
65
75
|
@params || {}
|
|
66
76
|
end
|
|
67
77
|
|
|
78
|
+
def clear_recipient
|
|
79
|
+
self.recipient = nil
|
|
80
|
+
end
|
|
81
|
+
|
|
68
82
|
private
|
|
69
83
|
|
|
70
84
|
# Runs all delivery methods for a notification
|
|
71
85
|
def run_delivery(recipient, enqueue: true)
|
|
72
86
|
delivery_methods = self.class.delivery_methods.dup
|
|
73
87
|
|
|
74
|
-
|
|
75
|
-
@recipient = recipient
|
|
88
|
+
self.recipient = recipient
|
|
76
89
|
|
|
77
90
|
# Run database delivery inline first if it exists so other methods have access to the record
|
|
78
91
|
if (index = delivery_methods.find_index { |m| m[:name] == :database })
|
|
79
92
|
delivery_method = delivery_methods.delete_at(index)
|
|
80
|
-
|
|
93
|
+
self.record = run_delivery_method(delivery_method, recipient: recipient, enqueue: false, record: nil)
|
|
81
94
|
end
|
|
82
95
|
|
|
83
96
|
delivery_methods.each do |delivery_method|
|
|
84
|
-
run_delivery_method(delivery_method, recipient: recipient, enqueue: enqueue)
|
|
97
|
+
run_delivery_method(delivery_method, recipient: recipient, enqueue: enqueue, record: record)
|
|
85
98
|
end
|
|
86
99
|
end
|
|
87
100
|
|
|
88
101
|
# Actually runs an individual delivery
|
|
89
|
-
def run_delivery_method(delivery_method, recipient:, enqueue:)
|
|
102
|
+
def run_delivery_method(delivery_method, recipient:, enqueue:, record:)
|
|
90
103
|
args = {
|
|
91
104
|
notification_class: self.class.name,
|
|
92
105
|
options: delivery_method[:options],
|
|
@@ -103,6 +116,9 @@ module Noticed
|
|
|
103
116
|
|
|
104
117
|
# Always perfrom later if a delay is present
|
|
105
118
|
if (delay = delivery_method.dig(:options, :delay))
|
|
119
|
+
# Dynamic delays with metho calls or
|
|
120
|
+
delay = send(delay) if delay.is_a? Symbol
|
|
121
|
+
|
|
106
122
|
method.set(wait: delay, queue: queue).perform_later(args)
|
|
107
123
|
elsif enqueue
|
|
108
124
|
method.set(queue: queue).perform_later(args)
|
data/lib/noticed/coder.rb
CHANGED
|
@@ -2,7 +2,7 @@ module Noticed
|
|
|
2
2
|
module DeliveryMethods
|
|
3
3
|
class ActionCable < Base
|
|
4
4
|
def deliver
|
|
5
|
-
channel.broadcast_to
|
|
5
|
+
channel.broadcast_to stream, format
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
private
|
|
@@ -30,6 +30,18 @@ module Noticed
|
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
|
+
|
|
34
|
+
def stream
|
|
35
|
+
value = options[:stream]
|
|
36
|
+
case value
|
|
37
|
+
when String
|
|
38
|
+
value
|
|
39
|
+
when Symbol
|
|
40
|
+
notification.send(value)
|
|
41
|
+
else
|
|
42
|
+
recipient
|
|
43
|
+
end
|
|
44
|
+
end
|
|
33
45
|
end
|
|
34
46
|
end
|
|
35
47
|
end
|