noticent 0.0.1.pre.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +51 -0
  3. data/.rubocop.yml +7 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +2 -0
  6. data/.vscode/settings.json +5 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +124 -0
  9. data/README.md +391 -0
  10. data/Rakefile +2 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/lib/generators/noticent/noticent.rb +36 -0
  14. data/lib/generators/noticent/templates/create_opt_ins.rb +15 -0
  15. data/lib/generators/noticent/templates/noticent_initializer.rb +17 -0
  16. data/lib/generators/noticent/templates/opt_in.rb +14 -0
  17. data/lib/noticent/active_record_opt_in_provider.rb +37 -0
  18. data/lib/noticent/channel.rb +75 -0
  19. data/lib/noticent/config.rb +209 -0
  20. data/lib/noticent/definitions/alert.rb +64 -0
  21. data/lib/noticent/definitions/channel.rb +43 -0
  22. data/lib/noticent/definitions/hooks.rb +38 -0
  23. data/lib/noticent/definitions/product.rb +16 -0
  24. data/lib/noticent/definitions/product_group.rb +44 -0
  25. data/lib/noticent/definitions/scope.rb +52 -0
  26. data/lib/noticent/dispatcher.rb +76 -0
  27. data/lib/noticent/errors.rb +17 -0
  28. data/lib/noticent/opt_in.rb +18 -0
  29. data/lib/noticent/proc_map.rb +35 -0
  30. data/lib/noticent/version.rb +5 -0
  31. data/lib/noticent/view.rb +82 -0
  32. data/lib/noticent.rb +9 -0
  33. data/noticent.gemspec +36 -0
  34. data/testing/channels/boo.rb +15 -0
  35. data/testing/channels/email.rb +20 -0
  36. data/testing/channels/foo.rb +12 -0
  37. data/testing/channels/slack.rb +10 -0
  38. data/testing/channels/webhook.rb +10 -0
  39. data/testing/models/receipient.rb +10 -0
  40. data/testing/payloads/comment_payload.rb +8 -0
  41. data/testing/payloads/payload.rb +9 -0
  42. data/testing/payloads/post_payload.rb +21 -0
  43. data/testing/views/email/some_event.html.erb +6 -0
  44. data/testing/views/email/some_event.txt.erb +6 -0
  45. data/testing/views/layouts/layout.html.erb +5 -0
  46. 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
@@ -0,0 +1,7 @@
1
+ require: rubocop-performance
2
+ Metrics/LineLength:
3
+ Max: 150
4
+ Metrics/BlockLength:
5
+ Max: 150
6
+ Metrics/CyclomaticComplexity:
7
+ Max: 12
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ noticent
data/.ruby-version ADDED
@@ -0,0 +1,2 @@
1
+ ruby-2.5.5
2
+
@@ -0,0 +1,5 @@
1
+ {
2
+ "cSpell.words": [
3
+ "Noticent"
4
+ ]
5
+ }
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in noticent.gemspec
4
+ gemspec
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
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
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,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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