noticed 1.2.19 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +61 -35
- data/lib/generators/noticed/model_generator.rb +2 -3
- data/lib/noticed.rb +1 -0
- data/lib/noticed/base.rb +7 -2
- data/lib/noticed/delivery_methods/email.rb +3 -5
- data/lib/noticed/engine.rb +5 -0
- data/lib/noticed/has_notifications.rb +32 -0
- data/lib/noticed/model.rb +9 -1
- data/lib/noticed/version.rb +1 -1
- metadata +32 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2362015405a07454aa743ec5709ede4af768866abf27499dce3754b37ac6f4f9
|
4
|
+
data.tar.gz: 05e36982fe6d3ed4d3cca6929271cc0382be5167fb4c6967396ae6969f3059fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea23c339c18177f234c2d541ababb78cda5ec408100ff828e6a1cd5678dabbfabf6f1bc79c7a129edaf22286754e2e741e611c2b0fc319bcdac10e00fc6fd66f
|
7
|
+
data.tar.gz: 4f0f7b8c0552683e7e8014a36ebe1d724bfd97baa3056f8483a40a94881bbd4ecbe6527b15a9ce2875d24dba7a767ee88d474b986001bd9974c1eca249a2d6ff
|
data/README.md
CHANGED
@@ -265,7 +265,7 @@ Sends a Teams notification via webhook.
|
|
265
265
|
|
266
266
|
* `format: :format_for_teams` - *Optional*
|
267
267
|
|
268
|
-
Use a custom method to define the payload sent to
|
268
|
+
Use a custom method to define the payload sent to Microsoft Teams. Method should return a Hash.
|
269
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
270
|
|
271
271
|
```ruby
|
@@ -354,6 +354,33 @@ Sends an SMS notification via Vonage / Nexmo.
|
|
354
354
|
}
|
355
355
|
```
|
356
356
|
|
357
|
+
### Fallback Notifications
|
358
|
+
|
359
|
+
A common pattern is to deliver a notification via the database and then, after some time has passed, email the user if they have not yet read the notification. You can implement this functionality by combining multiple delivery methods, the `delay` option, and the conditional `if` / `unless` option.
|
360
|
+
|
361
|
+
```ruby
|
362
|
+
class CommentNotification < Noticed::Base
|
363
|
+
deliver_by :database
|
364
|
+
deliver_by :email, mailer: 'CommentMailer', delay: 15.minutes, unless: :read?
|
365
|
+
end
|
366
|
+
```
|
367
|
+
|
368
|
+
Here a notification will be created immediately in the database (for display directly in your app). If the notification has not been read after 15 minutes, the email notification will be sent. If the notification has already been read in the app, the email will be skipped.
|
369
|
+
|
370
|
+
You can also configure multiple fallback options:
|
371
|
+
|
372
|
+
```ruby
|
373
|
+
class CriticalSystemNotification < Noticed::Base
|
374
|
+
deliver_by :slack
|
375
|
+
deliver_by :email, mailer: 'CriticalSystemMailer', delay: 10.minutes, unless: :read?
|
376
|
+
deliver_by :twilio, delay: 20.minutes, unless: :read?
|
377
|
+
end
|
378
|
+
```
|
379
|
+
|
380
|
+
In this scenario, you can create an escalating notification that starts with a ping in Slack, then emails the team, and then finally sends an SMS to the on-call phone.
|
381
|
+
|
382
|
+
You can mix and match the options and delivery methods to suit your application specific needs.
|
383
|
+
|
357
384
|
### 🚚 Custom Delivery Methods
|
358
385
|
|
359
386
|
To generate a custom delivery method, simply run
|
@@ -464,10 +491,19 @@ Sorting notifications by newest first:
|
|
464
491
|
user.notifications.newest_first
|
465
492
|
```
|
466
493
|
|
467
|
-
|
494
|
+
Query for read or unread notifications:
|
495
|
+
|
496
|
+
```ruby
|
497
|
+
user.notifications.read
|
498
|
+
user.notifications.unread
|
499
|
+
```
|
500
|
+
|
501
|
+
|
502
|
+
Marking all notifications as read or unread:
|
468
503
|
|
469
504
|
```ruby
|
470
505
|
user.notifications.mark_as_read!
|
506
|
+
user.notifications.mark_as_unread!
|
471
507
|
```
|
472
508
|
|
473
509
|
#### Instance methods
|
@@ -498,53 +534,43 @@ Adding notification associations to your models makes querying and deleting noti
|
|
498
534
|
|
499
535
|
For example, in most cases, you'll want to delete notifications for records that are destroyed.
|
500
536
|
|
501
|
-
|
537
|
+
We'll need two associations for this:
|
502
538
|
|
503
|
-
|
539
|
+
1. Notifications where the record is the recipient
|
540
|
+
2. Notifications where the record is in the notification params
|
504
541
|
|
505
542
|
For example, we can query the notifications and delete them on destroy like so:
|
506
543
|
|
507
544
|
```ruby
|
508
545
|
class Post < ApplicationRecord
|
509
|
-
|
510
|
-
|
511
|
-
@notifications ||= Notification.where(params: { post: self })
|
512
|
-
|
513
|
-
# Or Postgres syntax to query the post key in the JSON column
|
514
|
-
# @notifications ||= Notification.where("params->'post' = ?", Noticed::Coder.dump(self).to_json)
|
515
|
-
end
|
546
|
+
# Standard association for deleting notifications when you're the recipient
|
547
|
+
has_many :notifications, as: :recipient, dependent: :destroy
|
516
548
|
|
517
|
-
|
549
|
+
# Helper for associating and destroying Notification records where(params: {post: self})
|
550
|
+
has_noticed_notifications
|
518
551
|
|
519
|
-
|
520
|
-
|
521
|
-
end
|
552
|
+
# 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, model: "Notification"
|
522
554
|
end
|
523
|
-
```
|
524
|
-
|
525
|
-
##### Polymorphic Association
|
526
555
|
|
527
|
-
|
556
|
+
# Create a CommentNotification with a post param
|
557
|
+
CommentNotification.with(post: @post).deliver(user)
|
558
|
+
# Lookup Notifications where params: {post: @post}
|
559
|
+
@post.notifications_as_post
|
528
560
|
|
529
|
-
|
530
|
-
|
531
|
-
|
561
|
+
CommentNotification.with(parent: @post).deliver(user)
|
562
|
+
@post.notifications_as_parent
|
563
|
+
```
|
532
564
|
|
533
|
-
|
565
|
+
#### Handling Deleted Records
|
534
566
|
|
535
|
-
|
536
|
-
class ExampleNotification < Noticed::Base
|
537
|
-
deliver_by :database, format: :format_for_database
|
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 discord the job on these errors by adding the following to `ApplicationJob`:
|
538
568
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
}
|
545
|
-
end
|
546
|
-
end
|
547
|
-
```
|
569
|
+
```ruby
|
570
|
+
class ApplicationJob < ActiveJob::Base
|
571
|
+
discard_on ActiveJob::DeserializationError
|
572
|
+
end
|
573
|
+
```
|
548
574
|
|
549
575
|
## 🙏 Contributing
|
550
576
|
|
@@ -43,12 +43,11 @@ module Noticed
|
|
43
43
|
|
44
44
|
def params_column
|
45
45
|
case ActiveRecord::Base.configurations.configs_for(spec_name: "primary").config["adapter"]
|
46
|
-
when "mysql2"
|
47
|
-
"params:json"
|
48
46
|
when "postgresql"
|
49
47
|
"params:jsonb"
|
50
48
|
else
|
51
|
-
|
49
|
+
# MySQL and SQLite both support json
|
50
|
+
"params:json"
|
52
51
|
end
|
53
52
|
end
|
54
53
|
end
|
data/lib/noticed.rb
CHANGED
@@ -5,6 +5,7 @@ require "noticed/engine"
|
|
5
5
|
module Noticed
|
6
6
|
autoload :Base, "noticed/base"
|
7
7
|
autoload :Coder, "noticed/coder"
|
8
|
+
autoload :HasNotifications, "noticed/has_notifications"
|
8
9
|
autoload :Model, "noticed/model"
|
9
10
|
autoload :TextCoder, "noticed/text_coder"
|
10
11
|
autoload :Translation, "noticed/translation"
|
data/lib/noticed/base.rb
CHANGED
@@ -12,6 +12,8 @@ module Noticed
|
|
12
12
|
# Gives notifications access to the record and recipient when formatting for delivery
|
13
13
|
attr_accessor :record, :recipient
|
14
14
|
|
15
|
+
delegate :read?, :unread?, to: :record
|
16
|
+
|
15
17
|
class << self
|
16
18
|
def deliver_by(name, options = {})
|
17
19
|
delivery_methods.push(name: name, options: options)
|
@@ -96,11 +98,14 @@ module Noticed
|
|
96
98
|
run_callbacks delivery_method[:name] do
|
97
99
|
method = delivery_method_for(delivery_method[:name], delivery_method[:options])
|
98
100
|
|
101
|
+
# If the queue is `nil`, ActiveJob will use a default queue name.
|
102
|
+
queue = delivery_method.dig(:options, :queue)
|
103
|
+
|
99
104
|
# Always perfrom later if a delay is present
|
100
105
|
if (delay = delivery_method.dig(:options, :delay))
|
101
|
-
method.set(wait: delay).perform_later(args)
|
106
|
+
method.set(wait: delay, queue: queue).perform_later(args)
|
102
107
|
elsif enqueue
|
103
|
-
method.perform_later(args)
|
108
|
+
method.set(queue: queue).perform_later(args)
|
104
109
|
else
|
105
110
|
method.perform_now(args)
|
106
111
|
end
|
@@ -18,14 +18,12 @@ module Noticed
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def format
|
21
|
-
if (method = options[:format])
|
21
|
+
params = if (method = options[:format])
|
22
22
|
notification.send(method)
|
23
23
|
else
|
24
|
-
notification.params
|
25
|
-
recipient: recipient,
|
26
|
-
record: record
|
27
|
-
)
|
24
|
+
notification.params
|
28
25
|
end
|
26
|
+
params.merge(recipient: recipient, record: record)
|
29
27
|
end
|
30
28
|
end
|
31
29
|
end
|
data/lib/noticed/engine.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Noticed
|
2
|
+
module HasNotifications
|
3
|
+
# Defines a method for the association and a before_destory callback to remove notifications
|
4
|
+
# where this record is a param
|
5
|
+
#
|
6
|
+
# class User < ApplicationRecord
|
7
|
+
# has_noticed_notifications
|
8
|
+
# has_noticed_notifications param_name: :owner, destroy: false, model: "Notification"
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# @user.notifications_as_user
|
12
|
+
# @user.notifications_as_owner
|
13
|
+
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
|
16
|
+
class_methods do
|
17
|
+
def has_noticed_notifications(param_name: model_name.singular, **options)
|
18
|
+
model = options.fetch(:model_name, "Notification").constantize
|
19
|
+
|
20
|
+
define_method "notifications_as_#{param_name}" do
|
21
|
+
model.where(params: {param_name.to_sym => self})
|
22
|
+
end
|
23
|
+
|
24
|
+
if options.fetch(:destroy, true)
|
25
|
+
before_destroy do
|
26
|
+
send("notifications_as_#{param_name}").destroy_all
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/noticed/model.rb
CHANGED
@@ -14,18 +14,26 @@ module Noticed
|
|
14
14
|
scope :read, -> { where.not(read_at: nil) }
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
class_methods do
|
18
18
|
def mark_as_read!
|
19
19
|
update_all(read_at: Time.current, updated_at: Time.current)
|
20
20
|
end
|
21
21
|
|
22
|
+
def mark_as_unread!
|
23
|
+
update_all(read_at: nil, updated_at: Time.current)
|
24
|
+
end
|
25
|
+
|
22
26
|
def noticed_coder
|
27
|
+
return Noticed::TextCoder unless table_exists?
|
28
|
+
|
23
29
|
case attribute_types["params"].type
|
24
30
|
when :json, :jsonb
|
25
31
|
Noticed::Coder
|
26
32
|
else
|
27
33
|
Noticed::TextCoder
|
28
34
|
end
|
35
|
+
rescue ActiveRecord::NoDatabaseError
|
36
|
+
Noticed::TextCoder
|
29
37
|
end
|
30
38
|
end
|
31
39
|
|
data/lib/noticed/version.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: 1.2
|
4
|
+
version: 1.3.2
|
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: 2021-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -80,6 +80,34 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: mysql2
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sqlite3
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
description: Database, browser, realtime ActionCable, Email, SMS, Slack notifications,
|
84
112
|
and more for Rails apps
|
85
113
|
email:
|
@@ -110,6 +138,7 @@ files:
|
|
110
138
|
- lib/noticed/delivery_methods/twilio.rb
|
111
139
|
- lib/noticed/delivery_methods/vonage.rb
|
112
140
|
- lib/noticed/engine.rb
|
141
|
+
- lib/noticed/has_notifications.rb
|
113
142
|
- lib/noticed/model.rb
|
114
143
|
- lib/noticed/notification_channel.rb
|
115
144
|
- lib/noticed/text_coder.rb
|
@@ -135,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
164
|
- !ruby/object:Gem::Version
|
136
165
|
version: '0'
|
137
166
|
requirements: []
|
138
|
-
rubygems_version: 3.
|
167
|
+
rubygems_version: 3.2.3
|
139
168
|
signing_key:
|
140
169
|
specification_version: 4
|
141
170
|
summary: Notifications for Ruby on Rails applications
|