noticent 0.0.1.pre.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +51 -0
- data/.rubocop.yml +7 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +2 -0
- data/.vscode/settings.json +5 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +124 -0
- data/README.md +391 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/generators/noticent/noticent.rb +36 -0
- data/lib/generators/noticent/templates/create_opt_ins.rb +15 -0
- data/lib/generators/noticent/templates/noticent_initializer.rb +17 -0
- data/lib/generators/noticent/templates/opt_in.rb +14 -0
- data/lib/noticent/active_record_opt_in_provider.rb +37 -0
- data/lib/noticent/channel.rb +75 -0
- data/lib/noticent/config.rb +209 -0
- data/lib/noticent/definitions/alert.rb +64 -0
- data/lib/noticent/definitions/channel.rb +43 -0
- data/lib/noticent/definitions/hooks.rb +38 -0
- data/lib/noticent/definitions/product.rb +16 -0
- data/lib/noticent/definitions/product_group.rb +44 -0
- data/lib/noticent/definitions/scope.rb +52 -0
- data/lib/noticent/dispatcher.rb +76 -0
- data/lib/noticent/errors.rb +17 -0
- data/lib/noticent/opt_in.rb +18 -0
- data/lib/noticent/proc_map.rb +35 -0
- data/lib/noticent/version.rb +5 -0
- data/lib/noticent/view.rb +82 -0
- data/lib/noticent.rb +9 -0
- data/noticent.gemspec +36 -0
- data/testing/channels/boo.rb +15 -0
- data/testing/channels/email.rb +20 -0
- data/testing/channels/foo.rb +12 -0
- data/testing/channels/slack.rb +10 -0
- data/testing/channels/webhook.rb +10 -0
- data/testing/models/receipient.rb +10 -0
- data/testing/payloads/comment_payload.rb +8 -0
- data/testing/payloads/payload.rb +9 -0
- data/testing/payloads/post_payload.rb +21 -0
- data/testing/views/email/some_event.html.erb +6 -0
- data/testing/views/email/some_event.txt.erb +6 -0
- data/testing/views/layouts/layout.html.erb +5 -0
- metadata +241 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: fd327429401742c18e50a9ca5d13db9c34095f714ff89a6c8604a251272ede32
|
4
|
+
data.tar.gz: 39e4437f0c0cddecb782477196fb92b7c511a8866c5d081425595341c547771b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4a871931c9e904b314e55e4ec820dacfed2d42b00c902b74e0b87913d3c19b5f85f46d8c330fb68e63c2513f0bbfdc4da6cd8bfbc574e408afc1b2ab53bedfac
|
7
|
+
data.tar.gz: b42f22b75273b924a5f5d56f9d01891842018b63fc3a7e22326cc794d7d8f6833f255c136803ddbadc59009b7e269c8d0c0bd6fb88d24092430c2528ff771b6b
|
data/.gitignore
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
# Used by dotenv library to load environment variables.
|
14
|
+
# .env
|
15
|
+
|
16
|
+
## Specific to RubyMotion:
|
17
|
+
.dat*
|
18
|
+
.repl_history
|
19
|
+
build/
|
20
|
+
*.bridgesupport
|
21
|
+
build-iPhoneOS/
|
22
|
+
build-iPhoneSimulator/
|
23
|
+
|
24
|
+
## Specific to RubyMotion (use of CocoaPods):
|
25
|
+
#
|
26
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
27
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
28
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
29
|
+
#
|
30
|
+
# vendor/Pods/
|
31
|
+
|
32
|
+
## Documentation cache and generated files:
|
33
|
+
/.yardoc/
|
34
|
+
/_yardoc/
|
35
|
+
/doc/
|
36
|
+
/rdoc/
|
37
|
+
|
38
|
+
## Environment normalization:
|
39
|
+
/.bundle/
|
40
|
+
/vendor/bundle
|
41
|
+
/lib/bundler/man/
|
42
|
+
|
43
|
+
# for a library or gem, you might want to ignore these files since the code is
|
44
|
+
# intended to run in multiple environments; otherwise, check them in:
|
45
|
+
# Gemfile.lock
|
46
|
+
# .ruby-version
|
47
|
+
# .ruby-gemset
|
48
|
+
|
49
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
50
|
+
.rvmrc
|
51
|
+
/.idea
|
data/.rubocop.yml
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
noticent
|
data/.ruby-version
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
noticent (0.0.1.pre.pre)
|
5
|
+
activerecord (~> 5.2)
|
6
|
+
activesupport (~> 5.2)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actionpack (5.2.3)
|
12
|
+
actionview (= 5.2.3)
|
13
|
+
activesupport (= 5.2.3)
|
14
|
+
rack (~> 2.0)
|
15
|
+
rack-test (>= 0.6.3)
|
16
|
+
rails-dom-testing (~> 2.0)
|
17
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
18
|
+
actionview (5.2.3)
|
19
|
+
activesupport (= 5.2.3)
|
20
|
+
builder (~> 3.1)
|
21
|
+
erubi (~> 1.4)
|
22
|
+
rails-dom-testing (~> 2.0)
|
23
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
24
|
+
activemodel (5.2.3)
|
25
|
+
activesupport (= 5.2.3)
|
26
|
+
activerecord (5.2.3)
|
27
|
+
activemodel (= 5.2.3)
|
28
|
+
activesupport (= 5.2.3)
|
29
|
+
arel (>= 9.0)
|
30
|
+
activesupport (5.2.3)
|
31
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
32
|
+
i18n (>= 0.7, < 2)
|
33
|
+
minitest (~> 5.1)
|
34
|
+
tzinfo (~> 1.1)
|
35
|
+
arel (9.0.0)
|
36
|
+
ast (2.4.0)
|
37
|
+
builder (3.2.3)
|
38
|
+
concurrent-ruby (1.1.5)
|
39
|
+
crass (1.0.4)
|
40
|
+
diff-lcs (1.3)
|
41
|
+
erubi (1.8.0)
|
42
|
+
factory_bot (5.0.2)
|
43
|
+
activesupport (>= 4.2.0)
|
44
|
+
generator_spec (0.9.4)
|
45
|
+
activesupport (>= 3.0.0)
|
46
|
+
railties (>= 3.0.0)
|
47
|
+
i18n (1.6.0)
|
48
|
+
concurrent-ruby (~> 1.0)
|
49
|
+
jaro_winkler (1.5.2)
|
50
|
+
loofah (2.2.3)
|
51
|
+
crass (~> 1.0.2)
|
52
|
+
nokogiri (>= 1.5.9)
|
53
|
+
method_source (0.9.2)
|
54
|
+
mini_portile2 (2.4.0)
|
55
|
+
minitest (5.11.3)
|
56
|
+
nokogiri (1.10.3)
|
57
|
+
mini_portile2 (~> 2.4.0)
|
58
|
+
parallel (1.17.0)
|
59
|
+
parser (2.6.3.0)
|
60
|
+
ast (~> 2.4.0)
|
61
|
+
rack (2.0.7)
|
62
|
+
rack-test (1.1.0)
|
63
|
+
rack (>= 1.0, < 3)
|
64
|
+
rails-dom-testing (2.0.3)
|
65
|
+
activesupport (>= 4.2.0)
|
66
|
+
nokogiri (>= 1.6)
|
67
|
+
rails-html-sanitizer (1.0.4)
|
68
|
+
loofah (~> 2.2, >= 2.2.2)
|
69
|
+
railties (5.2.3)
|
70
|
+
actionpack (= 5.2.3)
|
71
|
+
activesupport (= 5.2.3)
|
72
|
+
method_source
|
73
|
+
rake (>= 0.8.7)
|
74
|
+
thor (>= 0.19.0, < 2.0)
|
75
|
+
rainbow (3.0.0)
|
76
|
+
rake (10.5.0)
|
77
|
+
rspec (3.8.0)
|
78
|
+
rspec-core (~> 3.8.0)
|
79
|
+
rspec-expectations (~> 3.8.0)
|
80
|
+
rspec-mocks (~> 3.8.0)
|
81
|
+
rspec-core (3.8.0)
|
82
|
+
rspec-support (~> 3.8.0)
|
83
|
+
rspec-expectations (3.8.3)
|
84
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
85
|
+
rspec-support (~> 3.8.0)
|
86
|
+
rspec-mocks (3.8.0)
|
87
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
88
|
+
rspec-support (~> 3.8.0)
|
89
|
+
rspec-support (3.8.0)
|
90
|
+
rubocop (0.69.0)
|
91
|
+
jaro_winkler (~> 1.5.1)
|
92
|
+
parallel (~> 1.10)
|
93
|
+
parser (>= 2.6)
|
94
|
+
rainbow (>= 2.2.2, < 4.0)
|
95
|
+
ruby-progressbar (~> 1.7)
|
96
|
+
unicode-display_width (>= 1.4.0, < 1.7)
|
97
|
+
rubocop-performance (1.3.0)
|
98
|
+
rubocop (>= 0.68.0)
|
99
|
+
ruby-progressbar (1.10.0)
|
100
|
+
rufo (0.7.0)
|
101
|
+
sqlite3 (1.4.1)
|
102
|
+
thor (0.20.3)
|
103
|
+
thread_safe (0.3.6)
|
104
|
+
tzinfo (1.2.5)
|
105
|
+
thread_safe (~> 0.1)
|
106
|
+
unicode-display_width (1.6.0)
|
107
|
+
|
108
|
+
PLATFORMS
|
109
|
+
ruby
|
110
|
+
|
111
|
+
DEPENDENCIES
|
112
|
+
bundler (~> 2.0)
|
113
|
+
factory_bot (~> 5.0)
|
114
|
+
generator_spec (~> 0.9)
|
115
|
+
noticent!
|
116
|
+
rake (~> 10.0)
|
117
|
+
rspec (~> 3.8)
|
118
|
+
rubocop (~> 0.69)
|
119
|
+
rubocop-performance (~> 1.3)
|
120
|
+
rufo (~> 0.7)
|
121
|
+
sqlite3 (~> 1.4)
|
122
|
+
|
123
|
+
BUNDLED WITH
|
124
|
+
2.0.1
|
data/README.md
ADDED
@@ -0,0 +1,391 @@
|
|
1
|
+
# Noticent
|
2
|
+
|
3
|
+
Noticent is a Ruby gem for user notification management. It is written to deliver a developer friendly way to managing application notifications in a typical web application. Many applications have user notification: sending emails when a task is done or support for webhooks or Slack upon certain events. Noticent makes it easy to write maintainable code for notification subscription and delivery in a typical web application.
|
4
|
+
|
5
|
+
[![Codeship Status for cloud66-oss/noticent](https://app.codeship.com/projects/f5bd9b70-646f-0137-d7e7-7232cc99892f/status?branch=master)](https://app.codeship.com/projects/344893)
|
6
|
+
|
7
|
+
The primary design goal for Noticent is developer friendliness. Using Noticent, you should be able to:
|
8
|
+
|
9
|
+
- Create new notification types
|
10
|
+
- Tell the current state of notifications, subscriptions and distribution channels.
|
11
|
+
- Support multiple notification channels like email, chat applications, mobile push, webhooks and more.
|
12
|
+
- Test your notifications
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'noticent'
|
20
|
+
```
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
```bash
|
25
|
+
bundle
|
26
|
+
```
|
27
|
+
|
28
|
+
Or install it yourself as:
|
29
|
+
|
30
|
+
```bash
|
31
|
+
gem install noticent
|
32
|
+
```
|
33
|
+
|
34
|
+
### Run Generators
|
35
|
+
|
36
|
+
```bash
|
37
|
+
rails g noticent:install
|
38
|
+
```
|
39
|
+
|
40
|
+
Now run the migrations
|
41
|
+
|
42
|
+
```bash
|
43
|
+
rake db:migrate
|
44
|
+
```
|
45
|
+
|
46
|
+
## Usage
|
47
|
+
|
48
|
+
Noticent is written to be used in a Rails application but you should be able to use it in other Ruby / Rack based applications if you need to.
|
49
|
+
|
50
|
+
### Basics
|
51
|
+
|
52
|
+
Noticent uses the following concepts:
|
53
|
+
|
54
|
+
#### Alert
|
55
|
+
|
56
|
+
Alert is a type of notification. For example, a new user signing up could be defined as an Alert.
|
57
|
+
|
58
|
+
#### Scope
|
59
|
+
|
60
|
+
Scope is like a namespace for Alerts. In many applications, you will only have 1 Scope. However, sometimes you might have different types of Alerts for different parts of your application. For example, "new blog post written" and "blog post updated" Alerts could be associated with the a "blog" Scope, while a "new comment added" Alert is associated with another Scope. Using Scope is useful when you have many different groups of Alerts in your application.
|
61
|
+
|
62
|
+
#### Channel
|
63
|
+
|
64
|
+
Channel is a distribution channel for your Alerts. Examples of Channels are Email, Slack, Webhook, Mobile or browser notification.
|
65
|
+
|
66
|
+
#### Recipient
|
67
|
+
|
68
|
+
Recipient is a person or system that receives Alerts. This could be a user for Channels like Email or a system for a Webhook Channel.
|
69
|
+
|
70
|
+
#### Payload
|
71
|
+
|
72
|
+
Payload is a data structure (class) that carries everything you'd need to send an Alert to a Recipient over a Channel.
|
73
|
+
|
74
|
+
#### Product
|
75
|
+
|
76
|
+
A product acts as a filter on alerts. For example, you might want to list different set of alerts for different parts of your application. To achieve that you can define each part as a product and use `applies.to` and `applies.not_to` to say how an alert applies to each part of the application.
|
77
|
+
Products don't have an effect on how alerts are run, but they can be used to list which alerts apply to each part of an application using `Noticent.configuration.product_by_alert` method.
|
78
|
+
|
79
|
+
If an alert doesn't have an `applies`, it will be applicable to none of the products defined.
|
80
|
+
|
81
|
+
### Integration
|
82
|
+
|
83
|
+
Noticent tries to make very few assumptions about your application, like what you call your Recipients or what your Scopes are. However it also enforces some opinions to make the whole system easier to use and maintain.
|
84
|
+
|
85
|
+
### Configuration
|
86
|
+
|
87
|
+
The most important part of using Noticent is the configuration part where you define scopes, channels and your alerts. Once configured, you can hook it up to the rest of your code. This example assumes integration in a Rails application.
|
88
|
+
|
89
|
+
If you have run the generators, you should now have a file called `config/initializers/noticent.rb`. You can edit it as you like:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
Noticent.configure do
|
93
|
+
channel :email
|
94
|
+
|
95
|
+
scope :account do
|
96
|
+
alert :new_signup do
|
97
|
+
notify :owner
|
98
|
+
end
|
99
|
+
alert :new_team_member do
|
100
|
+
notify :users
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
Now you'd need to tell Noticent how to send emails by creating an email channel. This can be done in `app/models/noticent/channels/email.rb`:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
class Email < ::Noticent::Channel
|
110
|
+
def new_signup
|
111
|
+
# send email here
|
112
|
+
end
|
113
|
+
|
114
|
+
def new_team_member
|
115
|
+
# send email here
|
116
|
+
end
|
117
|
+
end
|
118
|
+
```
|
119
|
+
|
120
|
+
Now that we have our channel, we can define a Payload. We can do this in `app/modesl/noticent/account_payload.rb`:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
class AccountPayload
|
124
|
+
attr_reader :account
|
125
|
+
attr_reader :current_user
|
126
|
+
|
127
|
+
def initializer(account_id, current_user)
|
128
|
+
@account = Account.find account_id
|
129
|
+
end
|
130
|
+
|
131
|
+
def users
|
132
|
+
@account.users
|
133
|
+
end
|
134
|
+
|
135
|
+
def owner
|
136
|
+
@account.owner
|
137
|
+
end
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
You can now create your email templates in `app/models/noticent/views/email` with 2 files called `new_signup.html.erb` and `new_team_member.html.erb` the same way you would write email templates for Rails mailers:
|
142
|
+
|
143
|
+
```html
|
144
|
+
Hello <%= @owner.name %>!
|
145
|
+
A new user just signed up.
|
146
|
+
```
|
147
|
+
|
148
|
+
and
|
149
|
+
|
150
|
+
```html
|
151
|
+
You now have a new team member. Make sure to say hi!
|
152
|
+
```
|
153
|
+
|
154
|
+
Until now, this is very much like Rail's own mailers and follows the same principles: Payload is like a model, Channel is the equivalent of a controller and the html view file is the view.
|
155
|
+
|
156
|
+
This first difference here is that you can use "front matter" in your views. This is useful when you need more than just text or HTML in your notifications. For an email channel, the front matter can hold a template for the email subject for example:
|
157
|
+
|
158
|
+
```html
|
159
|
+
subject: New member for <%= @team.name %>
|
160
|
+
---
|
161
|
+
Hello!
|
162
|
+
|
163
|
+
You now have a new team member who signed up as an admin for <%= @team.name %>
|
164
|
+
```
|
165
|
+
|
166
|
+
In the channel, you can use this:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
class EmailChannel < ::Noticent::Channel
|
170
|
+
|
171
|
+
def new_member
|
172
|
+
data, content = render
|
173
|
+
send_email(subject: data[:subject], content: content) # this is an example code
|
174
|
+
end
|
175
|
+
end
|
176
|
+
```
|
177
|
+
|
178
|
+
The `render` method looks for the right file under the `views` directory and loads and renders the ERB file while returning any front matter if available.
|
179
|
+
|
180
|
+
Use of front matter becomes more important in channels that have a more complex API like Slack (message color can be stored in the front matter) for example.
|
181
|
+
|
182
|
+
Now let's go back to our configuration file and see what else we can do. Here is an example of a Noticent configuration file in full:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
Noticent.configure do
|
186
|
+
hooks :pre_channel_registration, my_hooks
|
187
|
+
hooks :post_alert_registration, my_hooks
|
188
|
+
|
189
|
+
channel :email
|
190
|
+
channel :slack
|
191
|
+
channel :webhook, klass: MyWebhookChannel
|
192
|
+
channel :dashboard, group: :internal
|
193
|
+
|
194
|
+
product :product_foo
|
195
|
+
product :product_buzz
|
196
|
+
product :product_bar
|
197
|
+
|
198
|
+
scope :account do
|
199
|
+
alert :new_user do
|
200
|
+
applies.to :product_foo
|
201
|
+
notify :users
|
202
|
+
notify(:staff).on(:internal)
|
203
|
+
notify :owners
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
scope :comment do
|
208
|
+
alert :new_comment do
|
209
|
+
applies.not_to :product_buzz
|
210
|
+
notify :commenter
|
211
|
+
notify :auther
|
212
|
+
end
|
213
|
+
alert :comment_updated do
|
214
|
+
notify :commenter
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
scope :staff_comment, payload_class: AnotherPayloadClass do
|
219
|
+
alert :marked_as_answer do
|
220
|
+
notify(:staff).on(:internal)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
```
|
225
|
+
|
226
|
+
### Sending Alerts
|
227
|
+
|
228
|
+
To send an Alert, call the `notify` method:
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
account_payload = AccountPayload.new(1, user.first)
|
232
|
+
Noticent.notify(:new_user, account_payload)
|
233
|
+
```
|
234
|
+
|
235
|
+
### Using Each Noticent Component
|
236
|
+
|
237
|
+
#### Payload
|
238
|
+
|
239
|
+
To understand how to use Noticent, it's important to know the conventions it uses. First, payloads: A payload is a class and should have methods named after each one of the recipient groups specified in the configuration. For example, if an alert should be sent to `users` then payload should have a method or attribute called `users`. This method is called at the point the notifications need to be sent to retrieve the recipients. It is up to you what each recipient is: it could be an email address (string) or the entire user object or an ID. Your channel class will be given this and should know how to handle it.
|
240
|
+
|
241
|
+
It is recommended to explicitly define the class type of each scope. This ensures integrity of the alerts in runtime:
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
Noticent.configure do
|
245
|
+
scope :account, payload_class: SomeOtherClass do
|
246
|
+
#...
|
247
|
+
end
|
248
|
+
end
|
249
|
+
```
|
250
|
+
|
251
|
+
If specified, the type of the payload is checked against this class at runtime (when `Notify` is called).
|
252
|
+
|
253
|
+
#### Channel
|
254
|
+
|
255
|
+
Channels should be derived from `::Noticent::Channel` class and called the same as with the name of the channel with a `Channel` suffix: `email` would be `EmailChannel` and `slack` will be `SlackChannel`. Also, channels should have a method for each type of alert they are supposed to handle. Channel class can be changed using the `klass` argument during definition.
|
256
|
+
|
257
|
+
Channels can also have groups. If no group is supplied, a channel will belong to the `default` group. Groups can be used to send alerts to a subset of channels:
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
Noticent.configure do
|
261
|
+
channel :email
|
262
|
+
channel :private_emails, group: :internal
|
263
|
+
channel :slack
|
264
|
+
channel(:team_slack, klass: Slack, group: :internal) do
|
265
|
+
using(fuzz: :buzz)
|
266
|
+
end
|
267
|
+
|
268
|
+
alert :some_event do
|
269
|
+
notify :users
|
270
|
+
notify(:staff).on(:internal)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
```
|
274
|
+
|
275
|
+
In the example above, we are creating 2 flavors of the slack channel, one called `team_slack` but using the same class and configured differently. When `using` is used in a channel, any attribute passed into `using` will be called on the channel after creation with the given values.
|
276
|
+
For example, in this example, the `Slack` class is instantiated and attribute `fuzz` is set to `:buzz` on it before the alert method is called.
|
277
|
+
|
278
|
+
You can use `render` in the channel code to render and return the view file and its front matter (if available). By default, channel will look for `html` and `erb` as the file content and format. You can change these both when calling `render` or at the top of the controller:
|
279
|
+
|
280
|
+
```ruby
|
281
|
+
class SlackChannel < ::Noticent::Channel
|
282
|
+
default_format :json
|
283
|
+
default_ext :erb
|
284
|
+
end
|
285
|
+
```
|
286
|
+
|
287
|
+
or
|
288
|
+
|
289
|
+
```ruby
|
290
|
+
data, content = render(format: :erb, ext: :json)
|
291
|
+
```
|
292
|
+
|
293
|
+
You can also use a different layout for each render:
|
294
|
+
|
295
|
+
```ruby
|
296
|
+
data, content = render layout: 'my_layout'
|
297
|
+
```
|
298
|
+
|
299
|
+
By default, no layout is used.
|
300
|
+
|
301
|
+
#### Views
|
302
|
+
|
303
|
+
Views are like Rails views. Noticent supports rendering ERB files. You can also use layouts just like Rails. A layout is like a shared template `layout.html.erb`:
|
304
|
+
|
305
|
+
```html
|
306
|
+
This is at the top
|
307
|
+
|
308
|
+
<%= yield %>
|
309
|
+
|
310
|
+
This is at the bottom
|
311
|
+
```
|
312
|
+
|
313
|
+
`some_event.html.erb`:
|
314
|
+
|
315
|
+
```html
|
316
|
+
foo: bar
|
317
|
+
buzz: fuzz
|
318
|
+
---
|
319
|
+
This will be in the middle
|
320
|
+
```
|
321
|
+
|
322
|
+
Views can be of any type, like HTML or JSON which can be useful with API based channels.
|
323
|
+
|
324
|
+
## Opt-ins
|
325
|
+
|
326
|
+
Noticent uses a combination of channel, alert and scope to determine if a recipient has subscribed to receive an alert or not. By default it uses the `ActiveRecordOptInProvider` class which uses a single database table for the process. You can write your own Opt-in provider if you want to store subscription (opt-in) state in a different place. See `ActiveRecordOptInProvider` for what such provider requires to operate.
|
327
|
+
|
328
|
+
Use `Noticent.configuration.opt_in_provider`'s `opt_in`, `opt_out` and `opted_in?` methods to change the opt-in state of each recipient.
|
329
|
+
|
330
|
+
## Migration
|
331
|
+
|
332
|
+
Noticent provides a method to add new alerts or remove deprecated alerts from the existing recipients. To add a new alert type, you can use `ActiveRecordOptInProvider.add_alert` method:
|
333
|
+
|
334
|
+
```ruby
|
335
|
+
Noticent.opt_in_provider.add_alert(scope: :foo, alert_name: :some_new_alert, recipient_ids: [1, 2, 3, 5, 6], channel: :email)
|
336
|
+
```
|
337
|
+
|
338
|
+
This will opt-in recipients with the given IDs for the new alert on the `email` channel.
|
339
|
+
|
340
|
+
To remove any deprecated alert, use the `ActiveRecordOptInProvider.remove_alert` method:
|
341
|
+
|
342
|
+
```ruby
|
343
|
+
Noticent.opt_in_provider.remove_alert(scope: :foo, alert_name: :some_old_alert)
|
344
|
+
```
|
345
|
+
|
346
|
+
This removes all instances of the old alert from the opt-ins.
|
347
|
+
|
348
|
+
## Validation
|
349
|
+
|
350
|
+
Every time Noticent starts, it runs some validations on the configuration, classes that are defined, channels and alerts to make sure they are defined correctly and the supporting classes are in compliance with the requirements.
|
351
|
+
|
352
|
+
## Testing Your Alerts
|
353
|
+
|
354
|
+
TO BE WRITTEN
|
355
|
+
|
356
|
+
## Hooks
|
357
|
+
|
358
|
+
Hooks are extension points for Noticent. You can register them in your configuration:
|
359
|
+
|
360
|
+
```ruby
|
361
|
+
Noticent.configure do
|
362
|
+
hooks.add(:pre_channel_registration, custom_hook)
|
363
|
+
end
|
364
|
+
```
|
365
|
+
|
366
|
+
The valid hook points are `pre_channel_registration`, `post_channel_registration`, `pre_alert_registration` and `post_alert_registration`. Once the hook point is reached, the given object is called on the same method name as with the hook name.
|
367
|
+
|
368
|
+
## Customization
|
369
|
+
|
370
|
+
The following items can be customized:
|
371
|
+
|
372
|
+
`base_dir`: Base directory for all Noticent assets.
|
373
|
+
|
374
|
+
`base_module_name`: Base module name for all Noticent assets.
|
375
|
+
|
376
|
+
`opt_in_provider`: Opt-in provider class. Default is `ActiveRecordOptInProvider`.
|
377
|
+
|
378
|
+
`logger`: Logger class. Default is `stdout`
|
379
|
+
|
380
|
+
`halt_on_error`: Should notification fail after the first incident of an error during rendering. Default is `false`
|
381
|
+
|
382
|
+
|
383
|
+
## Development
|
384
|
+
|
385
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
386
|
+
|
387
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
388
|
+
|
389
|
+
## Contributing
|
390
|
+
|
391
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/khash/noticent.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "noticent"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
require 'rails/generators/migration'
|
5
|
+
|
6
|
+
module Noticent
|
7
|
+
module Generators
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
9
|
+
include Rails::Generators::Migration
|
10
|
+
|
11
|
+
source_root File.expand_path('templates', __dir__)
|
12
|
+
desc 'Generate Noticent required files'
|
13
|
+
def self.next_migration_number(path)
|
14
|
+
next_migration_number = current_migration_number(path) + 1
|
15
|
+
ActiveRecord::Migration.next_migration_number(next_migration_number)
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy_migrations
|
19
|
+
migration_template 'create_opt_ins.rb',
|
20
|
+
'db/migrate/create_opt_ins.rb'
|
21
|
+
|
22
|
+
puts 'DB migration generated. Run rake db:migrate next'
|
23
|
+
end
|
24
|
+
|
25
|
+
def copy_initializer
|
26
|
+
template 'noticent_initializer.rb', 'config/initializers/noticent.rb'
|
27
|
+
|
28
|
+
puts 'Install Complete!'
|
29
|
+
end
|
30
|
+
|
31
|
+
def copy_model
|
32
|
+
template 'opt_in.rb', 'app/models/opt_in.rb'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateOptIns < ActiveRecord::Migration[5.2]
|
2
|
+
def change
|
3
|
+
create_table :opt_ins, force: true do |t|
|
4
|
+
t.integer :recipient_id, null: false
|
5
|
+
t.integer :entity_id, null: false
|
6
|
+
t.string :scope, null: false
|
7
|
+
t.string :alert_name, null: false
|
8
|
+
t.string :channel_name, null: false
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
|
13
|
+
add_index :opt_ins, %i[recipient_id entity_id scope alert_name channel_name], unique: true, name: :unique_composite_key
|
14
|
+
end
|
15
|
+
end
|