hey-you 0.1.8 → 1.2.2
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/.travis.yml +3 -4
- data/CHANGELOG.md +13 -0
- data/README.md +77 -15
- data/hey_you.gemspec +1 -1
- data/lib/hey_you/builder.rb +39 -13
- data/lib/hey_you/builder/_base.rb +6 -3
- data/lib/hey_you/builder/email.rb +4 -0
- data/lib/hey_you/builder/push.rb +4 -0
- data/lib/hey_you/channels/_base.rb +4 -4
- data/lib/hey_you/channels/email.rb +31 -16
- data/lib/hey_you/config.rb +25 -31
- data/lib/hey_you/config/conigurable.rb +3 -2
- data/lib/hey_you/config/data_source.rb +38 -0
- data/lib/hey_you/config/email.rb +3 -3
- data/lib/hey_you/config/push.rb +1 -1
- data/lib/hey_you/data_source/_base.rb +9 -0
- data/lib/hey_you/data_source/hash.rb +17 -0
- data/lib/hey_you/data_source/yaml.rb +37 -0
- data/lib/hey_you/helper.rb +7 -0
- data/lib/hey_you/receiver.rb +9 -8
- data/lib/hey_you/sender.rb +17 -14
- data/lib/hey_you/version.rb +1 -1
- metadata +11 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 755f8775f2918592a3faf297f7dbed8f5b7253d137ac47ffedae9a9106a5d44f
|
|
4
|
+
data.tar.gz: 17c927968d8fe27c6a5e8b2ace86af1bb30683f3cc968099aca19401c94cbcd7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 592e4f17b2e26f26f04477150118a91d2cf68696bc17f3021617e554a14bddb19fd3fec5e2c8d2dc37342d045e6ca2c2c679969de645aa9269edf6cc139ea596
|
|
7
|
+
data.tar.gz: 83aa1a371cffa0efce33fb69e410abbe6d0eda85e019ab117f1e1ccb93cfee8d7ce92fb4b23d83a4b19d08615ccc0616c378ebd030801bc10b0773edb71e1596
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Changelog for hey-you gem
|
|
2
|
+
|
|
3
|
+
## 1.2.2
|
|
4
|
+
- Improvement: `if` condition for receiver (if condition `false` - sending will be skipped).
|
|
5
|
+
- Improvement: `force` option - send message independent on `if` condition.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### 1.2.1
|
|
9
|
+
- Improvement: Builder will not make channel builder if it skipped by only option
|
|
10
|
+
|
|
11
|
+
### 1.2.0
|
|
12
|
+
- Feature: data source extensions (check readme for more information).
|
|
13
|
+
__Attention__: You should rewrite your configuration for use yaml data source!
|
data/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
# HeyYou
|
|
1
|
+
# HeyYou
|
|
2
2
|
[](https://travis-ci.com/QNester/hey-you#)
|
|
3
|
+
[](https://badge.fury.io/rb/hey-you)
|
|
3
4
|
|
|
4
5
|
Send multichannel notifications with one command.
|
|
5
6
|
Сonvenient storage of notifications texts. Create your
|
|
@@ -19,7 +20,7 @@ him easy.
|
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
## Requirements
|
|
22
|
-
* Ruby 2.
|
|
23
|
+
* Ruby 2.5.0 min (rspec works with ruby 2.5.0, 2.6.0, 2.7.0)
|
|
23
24
|
* FCM - Gem send push notification using [fcm gem](https://github.com/spacialdb/fcm).
|
|
24
25
|
You need *fcm server key* to successful configure push notifications.
|
|
25
26
|
|
|
@@ -43,15 +44,20 @@ Or install it yourself as:
|
|
|
43
44
|
First, you must configure HeyYou. Example:
|
|
44
45
|
```ruby
|
|
45
46
|
HeyYou::Config.configure do
|
|
46
|
-
config.
|
|
47
|
+
config.data_source.options = { collection_files: ['config/notifications.yml'] }
|
|
47
48
|
config.email.from = 'noreply@example-mail.com'
|
|
48
49
|
config.push.fcm_token = 'fcm_server_key'
|
|
49
50
|
end
|
|
50
51
|
```
|
|
51
52
|
#### Required settings
|
|
52
53
|
Options for gem base work.
|
|
53
|
-
#####
|
|
54
|
-
* __config.
|
|
54
|
+
##### Data Source
|
|
55
|
+
* __config.data_source.source_class__ - Class implemented instance method `load_collections` returning hash (by default `HeyYou::DataSource::Yaml`)
|
|
56
|
+
* __config.data_source.options__ - Arguments for source_class. This options will be passed to init `source_class`
|
|
57
|
+
OR
|
|
58
|
+
* __config.data_source.source_instance__ - Instance of source class implemented `load_collections`
|
|
59
|
+
|
|
60
|
+
Read more about data source in [data source](#data-source-1).d
|
|
55
61
|
##### Push
|
|
56
62
|
* __config.push.fcm_token__ - Required setting for push channel. You can not send
|
|
57
63
|
push messages if setting was not set. You should set it to equal your fcm server key.
|
|
@@ -61,20 +67,23 @@ push messages if setting was not set. You should set it to equal your fcm server
|
|
|
61
67
|
#### Optional settings
|
|
62
68
|
Additional options for configure your notifications.
|
|
63
69
|
#### Base
|
|
64
|
-
* __config.env_collection_file__ - File contained all your notifications texts for
|
|
65
|
-
environment. You can set it like `notifications.#{ENV['APP_ENV]}.yml`
|
|
66
70
|
* __config.splitter__ - Chars for split notification keys for
|
|
67
71
|
builder. Default: `.`
|
|
68
72
|
* __config.registered_channels__ - Avialable channels for your
|
|
69
73
|
applications. Default: `[:push, :email]`
|
|
74
|
+
* __config.require_all_channels__ - Boolean. If true, when data for channel will not found in
|
|
75
|
+
file collection, error will be raised. Default: `false`
|
|
70
76
|
* __config.localization__ - Boolean. If true, hey-you begin support I18n locales for notifications collection. Your
|
|
71
|
-
notifications for build should be nested in `I18n.locale` key. For example:
|
|
77
|
+
notifications for build should be nested in `I18n.locale` key. Default: `false`. For example:
|
|
72
78
|
|
|
73
79
|
```ruby
|
|
74
80
|
# config/initializers/hey-you.rb
|
|
75
81
|
HeyYou::Config.configure do
|
|
76
82
|
...
|
|
77
|
-
|
|
83
|
+
i18n_files = Rails.application.config.i18n.available_locales.map do |locale|
|
|
84
|
+
"config/notifications/#{locale}.yml"
|
|
85
|
+
end
|
|
86
|
+
config.data_source.options = { collection_files: i18n_files }
|
|
78
87
|
...
|
|
79
88
|
end
|
|
80
89
|
```
|
|
@@ -124,7 +133,7 @@ Default 60
|
|
|
124
133
|
Default 30
|
|
125
134
|
##### Email
|
|
126
135
|
* __config.email.layout__ - default layout for email letters.
|
|
127
|
-
* __config.email.
|
|
136
|
+
* __config.email.use_default_mailing__ - use default mail sending or use custom mailer classes
|
|
128
137
|
* __config.email.default_mailer_class__ - default mailer class for email notifications
|
|
129
138
|
* __config.email.default_mailer_method__ - default mailer_method for mailer_class
|
|
130
139
|
* __config.email.default_delivery_method__ - expects, that mailer_method will build message and delivery_method will send it.
|
|
@@ -154,8 +163,8 @@ fetching values required to send notification. For push channel
|
|
|
154
163
|
expected that proc will return receiver's fcm registration id. For
|
|
155
164
|
email expected that proc will return receiver's email address.
|
|
156
165
|
|
|
157
|
-
You can pass options for receiver channels. You must pass proc with receive_data to `:subject` key and options
|
|
158
|
-
pass to `:options` key:
|
|
166
|
+
You can pass options and sending condition for receiver channels. You must pass proc with receive_data to `:subject` key and options
|
|
167
|
+
pass to `:options` key. `if` key should be passed for sending condition:
|
|
159
168
|
|
|
160
169
|
```ruby
|
|
161
170
|
class User < Model
|
|
@@ -163,7 +172,11 @@ class User < Model
|
|
|
163
172
|
|
|
164
173
|
receive(
|
|
165
174
|
push: -> { push_token.value },
|
|
166
|
-
email: {
|
|
175
|
+
email: {
|
|
176
|
+
subject: -> { email },
|
|
177
|
+
if: -> { email_notifications? },
|
|
178
|
+
options: { mailer_class: UserMailer, mailer_method: :notify! }
|
|
179
|
+
}
|
|
167
180
|
)
|
|
168
181
|
end
|
|
169
182
|
```
|
|
@@ -180,9 +193,18 @@ Last command will fetch notifications credentials for user instance
|
|
|
180
193
|
and will try to send SMS, Push and Email for it. What argument we pass
|
|
181
194
|
for method? This is string key for builder. Read next to understand it.
|
|
182
195
|
|
|
196
|
+
Sometimes you need send notification independent on user's notification settings. For this case you can use
|
|
197
|
+
`force` option in `#send_notification`:
|
|
198
|
+
```ruby
|
|
199
|
+
user = User.find(1)
|
|
200
|
+
user.settings.update!(email_notifications: false)
|
|
201
|
+
user.send_notification('for_users.hello') #=> will not send notification
|
|
202
|
+
user.send_notification('for_users.hello', force: true) #=> will send notification
|
|
203
|
+
```
|
|
204
|
+
|
|
183
205
|
### Build your notification
|
|
184
206
|
HeyYou Notification Builder - good system for store your notifications in one place.
|
|
185
|
-
|
|
207
|
+
By default you need create yml file with follow format:
|
|
186
208
|
```yaml
|
|
187
209
|
# config/notifications/collection.yml
|
|
188
210
|
any_key:
|
|
@@ -209,6 +231,46 @@ notification will send for all available channels for receiver:
|
|
|
209
231
|
1) Send push via fcm
|
|
210
232
|
2) Send email
|
|
211
233
|
|
|
234
|
+
#### Data Source
|
|
235
|
+
Often we need store our notification text in another data source, not int yml files. HeyYou has flexible
|
|
236
|
+
system for data source. All what you need - make your own provider source and pass it to config. For example:
|
|
237
|
+
|
|
238
|
+
```ruby
|
|
239
|
+
class NotificationText < ApplicationRecord
|
|
240
|
+
def self.load_collections
|
|
241
|
+
# load colelctions from database to hash
|
|
242
|
+
# THIS METHOD MUST returns hash!
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
```ruby
|
|
248
|
+
HeyYou::Config.configure do
|
|
249
|
+
# NotificationText is a rails model
|
|
250
|
+
config.data_source.source_instance = NotificationText
|
|
251
|
+
end
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
HeyYou will pull texts from database to memory with initialize your application after this configuration. Builder
|
|
255
|
+
will build your texts successfully.
|
|
256
|
+
|
|
257
|
+
HeyYou by default contains only two data sources:
|
|
258
|
+
1. `HeyYou::DataSource::Yaml` - for store notifications collections in data. For example:
|
|
259
|
+
```ruby
|
|
260
|
+
HeyYou::Config.configure do
|
|
261
|
+
config.data_source.source_class = HeyYou::DataSource::Yaml
|
|
262
|
+
config.data_source.options = { collection_files: ['config/notifications.yml'] }
|
|
263
|
+
end
|
|
264
|
+
```
|
|
265
|
+
2. `HeyYou::DataSource::Hash` - store notification everywhere you want and pass to HeyYou only hash
|
|
266
|
+
```ruby
|
|
267
|
+
config.data_source.source_class = HeyYou::DataSource::Yaml
|
|
268
|
+
config.data_source.options = { data: { welcome: { email: { ... }, push: { ... } } } }
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
__Pay attention__: for difference source we should pass difference options.
|
|
272
|
+
|
|
273
|
+
|
|
212
274
|
### Send notification
|
|
213
275
|
Receiver not only one way to send notification. You can send it using `HeyYou::Sender`.
|
|
214
276
|
Just use method `#send` for HeyYou::Sender and pass notification key and `to` options
|
|
@@ -359,7 +421,7 @@ in your channel config.
|
|
|
359
421
|
Now, when you will send notification, it will be send with your channel too.
|
|
360
422
|
|
|
361
423
|
## Extensions
|
|
362
|
-
* [Slack channel](https://github.com/QNester/hey-you)
|
|
424
|
+
* [Slack channel](https://github.com/QNester/hey-you-slack)
|
|
363
425
|
[](https://badge.fury.io/rb/hey-you-slack)
|
|
364
426
|
|
|
365
427
|
## Development
|
data/hey_you.gemspec
CHANGED
|
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
|
26
26
|
spec.add_runtime_dependency "mail", '~> 2.7'
|
|
27
27
|
spec.add_runtime_dependency "i18n", '~> 1.0'
|
|
28
28
|
|
|
29
|
-
spec.add_development_dependency "rake", '~>
|
|
29
|
+
spec.add_development_dependency "rake", '~> 13.0'
|
|
30
30
|
spec.add_development_dependency "rspec", '~> 3.7'
|
|
31
31
|
spec.add_development_dependency "webmock", '~> 3.4'
|
|
32
32
|
spec.add_development_dependency "ffaker", '~> 2.9'
|
data/lib/hey_you/builder.rb
CHANGED
|
@@ -1,31 +1,51 @@
|
|
|
1
1
|
require 'i18n'
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
require 'hey_you/helper'
|
|
3
|
+
require 'hey_you/builder/email'
|
|
4
|
+
require 'hey_you/builder/push'
|
|
4
5
|
|
|
5
6
|
module HeyYou
|
|
6
7
|
class Builder
|
|
7
|
-
|
|
8
|
+
include HeyYou::Helper
|
|
9
|
+
|
|
10
|
+
attr_reader :data, :options, :keys
|
|
8
11
|
|
|
9
12
|
# Load data from collection yaml via key and interpolate variables.
|
|
10
13
|
# Define methods for each registered channel. After initialize you can use
|
|
11
14
|
# `instance.<ch_name>`. It will be return instance of HeyYou::Builder::<YOUR_CHANNEL_NAME>
|
|
12
15
|
#
|
|
16
|
+
# Skip builder for excluded channels (not included in `only` option)
|
|
17
|
+
#
|
|
18
|
+
# @param [String] key - notification key for fetching notification data from collection
|
|
13
19
|
def initialize(key, **options)
|
|
14
20
|
@data = fetch_from_collection_by_key(key, options[:locale])
|
|
15
21
|
@options = options
|
|
16
22
|
config.registered_channels.each do |ch|
|
|
17
|
-
|
|
18
|
-
HeyYou::Builder.const_get("#{ch.downcase.capitalize}").new(data, key, options)
|
|
19
|
-
instance_variable_set("@#{ch}".to_sym, ch_builder)
|
|
20
|
-
|
|
21
|
-
define_ch_method(ch)
|
|
23
|
+
init_channel_builder(ch, key) if channel_allowed_by_only?(ch, options[:only])
|
|
22
24
|
end
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
private
|
|
26
28
|
|
|
27
|
-
def
|
|
28
|
-
|
|
29
|
+
def init_channel_builder(ch, key)
|
|
30
|
+
if config.require_all_channels
|
|
31
|
+
unless data[ch.to_s]
|
|
32
|
+
raise RequiredChannelNotFound, "For key #{key} and channel #{ch} data not exists in collection."
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
unless data[ch.to_s]
|
|
36
|
+
define_ch_method(ch, true)
|
|
37
|
+
return
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
ch_builder =
|
|
41
|
+
HeyYou::Builder.const_get("#{ch.downcase.capitalize}").new(data[ch.to_s], key, options)
|
|
42
|
+
instance_variable_set("@#{ch}".to_sym, ch_builder)
|
|
43
|
+
|
|
44
|
+
define_ch_method(ch)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def define_ch_method(ch, empty = false)
|
|
48
|
+
method_proc = empty ? -> { nil } : -> { instance_variable_get("@#{ch}".to_sym) }
|
|
29
49
|
self.class.send(:define_method, ch, method_proc)
|
|
30
50
|
end
|
|
31
51
|
|
|
@@ -37,15 +57,21 @@ module HeyYou
|
|
|
37
57
|
keys << locale
|
|
38
58
|
end
|
|
39
59
|
keys = keys + key.to_s.split(config.splitter)
|
|
40
|
-
keys.reduce(config.collection) do |memo, nested_key|
|
|
60
|
+
data = keys.reduce(config.collection) do |memo, nested_key|
|
|
41
61
|
memo[nested_key.to_s] if memo
|
|
42
62
|
end
|
|
63
|
+
return data if data
|
|
64
|
+
raise DataNotFound, "collection data not found for `#{keys.join(config.splitter)}`"
|
|
43
65
|
end
|
|
44
66
|
|
|
45
|
-
def
|
|
46
|
-
|
|
67
|
+
def channel_allowed_by_only?(ch, only)
|
|
68
|
+
return true unless only
|
|
69
|
+
return only.map(&:to_sym).include?(ch.to_sym) if only.is_a?(Array)
|
|
70
|
+
only.to_sym == ch.to_sym
|
|
47
71
|
end
|
|
48
72
|
|
|
49
73
|
class UnknownLocale < StandardError; end
|
|
74
|
+
class DataNotFound < StandardError; end
|
|
75
|
+
class RequiredChannelNotFound < StandardError; end
|
|
50
76
|
end
|
|
51
77
|
end
|
|
@@ -10,6 +10,11 @@ module HeyYou
|
|
|
10
10
|
build
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
def to_hash
|
|
14
|
+
raise NotImplementedError, 'Builder not implemented #to_hash method'
|
|
15
|
+
end
|
|
16
|
+
alias_method :to_h, :to_hash
|
|
17
|
+
|
|
13
18
|
private
|
|
14
19
|
|
|
15
20
|
def interpolate(notification_string, options)
|
|
@@ -18,10 +23,8 @@ module HeyYou
|
|
|
18
23
|
raise InterpolationError, "Failed build notification string `#{notification_string}`: #{err.message}"
|
|
19
24
|
end
|
|
20
25
|
|
|
21
|
-
def ch_data
|
|
22
|
-
data.fetch(current_builder_name)
|
|
23
|
-
end
|
|
24
26
|
|
|
27
|
+
alias ch_data data
|
|
25
28
|
alias channel_data ch_data
|
|
26
29
|
|
|
27
30
|
def ch_options
|
data/lib/hey_you/builder/push.rb
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
require 'hey_you/helper'
|
|
1
2
|
module HeyYou
|
|
2
3
|
module Channels
|
|
3
4
|
class Base
|
|
5
|
+
include HeyYou::Helper
|
|
6
|
+
extend HeyYou::Helper
|
|
7
|
+
|
|
4
8
|
class << self
|
|
5
9
|
def send!
|
|
6
10
|
raise NotImplementedError, 'You should define #send! method in your channel.'
|
|
@@ -25,10 +29,6 @@ module HeyYou
|
|
|
25
29
|
[]
|
|
26
30
|
end
|
|
27
31
|
|
|
28
|
-
def config
|
|
29
|
-
Config.config
|
|
30
|
-
end
|
|
31
|
-
|
|
32
32
|
def ch_name
|
|
33
33
|
self.class.name.split('::').last.downcase
|
|
34
34
|
end
|
|
@@ -6,31 +6,31 @@ module HeyYou
|
|
|
6
6
|
class Email < Base
|
|
7
7
|
class << self
|
|
8
8
|
def send!(builder, to:, **options)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
method = config.email.default_mailing ? :send_via_mail : :send_via_custom_class
|
|
9
|
+
method = config.email.use_default_mailing ? :send_via_mail : :send_via_custom_class
|
|
12
10
|
public_send(method, builder, to, options)
|
|
13
11
|
end
|
|
14
12
|
|
|
15
13
|
# Send email via custom class instance.
|
|
16
14
|
def send_via_custom_class(builder, to, **options)
|
|
17
15
|
mailer = mailer_class_from_builder(builder, options)
|
|
18
|
-
|
|
19
|
-
mailer_method = options[:mailer_method] ||
|
|
20
|
-
builder.email.mailer_method ||
|
|
21
|
-
config.email.default_mailer_method
|
|
22
|
-
|
|
16
|
+
mailer_method = mailer_method_from_builder(mailer, builder, options)
|
|
23
17
|
delivery_method = options[:delivery_method] ||
|
|
24
18
|
builder.email.delivery_method ||
|
|
25
19
|
config.email.default_delivery_method
|
|
26
20
|
|
|
27
21
|
log("Build mail via #{mailer}##{mailer_method}. Delivery with #{delivery_method}")
|
|
28
|
-
mailer_msg = mailer.public_send(mailer_method, data: builder.email, to: to)
|
|
29
|
-
mailer_msg.public_send(delivery_method)
|
|
22
|
+
mailer_msg = mailer.public_send(mailer_method, data: builder.email.to_hash, to: to)
|
|
23
|
+
return mailer_msg.public_send(delivery_method) if mailer_msg.respond_to?(delivery_method)
|
|
24
|
+
raise(
|
|
25
|
+
DeliveryMethodNotDefined,
|
|
26
|
+
"Instance of mailer #{mailer} with method #{mailer_method} not respond to #{delivery_method}"
|
|
27
|
+
)
|
|
30
28
|
end
|
|
31
29
|
|
|
32
30
|
# Send email with standard mail (gem 'mail')
|
|
33
31
|
def send_via_mail(builder, to, **_)
|
|
32
|
+
raise CredentialsNotExists unless credentials_present?
|
|
33
|
+
|
|
34
34
|
context = self
|
|
35
35
|
mail = Mail.new do
|
|
36
36
|
from HeyYou::Config.instance.email.from
|
|
@@ -74,14 +74,29 @@ module HeyYou
|
|
|
74
74
|
|
|
75
75
|
mailer
|
|
76
76
|
end
|
|
77
|
-
end
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
def mailer_method_from_builder(mailer_class, builder, **options)
|
|
79
|
+
mailer_method = options[:mailer_method] ||
|
|
80
|
+
builder.email.mailer_method ||
|
|
81
|
+
config.email.default_mailer_method
|
|
82
|
+
unless mailer_method
|
|
83
|
+
raise(
|
|
84
|
+
MailerMethodNotDefined,
|
|
85
|
+
'You must set mailer_method in notifications collection or pass :mailer_method option.'
|
|
86
|
+
)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
return mailer_method if mailer_class.respond_to?(mailer_method)
|
|
90
|
+
raise MailerMethodNotDefined, "Method ##{mailer_method} not defined for #{mailer_class}."
|
|
91
|
+
end
|
|
84
92
|
end
|
|
93
|
+
|
|
94
|
+
class CredentialsNotExists < StandardError; end
|
|
95
|
+
class ActionMailerClassNotDefined < StandardError; end
|
|
96
|
+
class MailerClassNotDefined < StandardError; end
|
|
97
|
+
class MailerMethodNotDefined < StandardError; end
|
|
98
|
+
class DeliveryMethodNotDefined < StandardError; end
|
|
99
|
+
|
|
85
100
|
end
|
|
86
101
|
end
|
|
87
102
|
end
|
data/lib/hey_you/config.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
require 'yaml'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
require 'hey_you/config/conigurable'
|
|
3
|
+
require 'hey_you/config/push'
|
|
4
|
+
require 'hey_you/config/email'
|
|
5
|
+
require 'hey_you/config/data_source'
|
|
5
6
|
|
|
6
7
|
#
|
|
7
8
|
# @config REQUIRED collection_file [String] - File path for general notifications file
|
|
@@ -17,7 +18,15 @@ module HeyYou
|
|
|
17
18
|
class Config
|
|
18
19
|
extend Configurable
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
DEFAULTS = {
|
|
22
|
+
registered_channels: %i[email push],
|
|
23
|
+
splitter: '.',
|
|
24
|
+
log_tag: 'HeyYou',
|
|
25
|
+
localization: false,
|
|
26
|
+
require_all_channels: false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
DEFAULT_REGISTERED_CHANNELS =
|
|
21
30
|
DEFAULT_SPLITTER = '.'
|
|
22
31
|
DEFAULT_GLOBAL_LOG_TAG = 'HeyYou'
|
|
23
32
|
DEFAULT_LOCALIZATION_FLAG = false
|
|
@@ -26,26 +35,20 @@ module HeyYou
|
|
|
26
35
|
|
|
27
36
|
attr_reader :collection, :env_collection, :configured, :registered_receivers
|
|
28
37
|
attr_accessor(
|
|
29
|
-
:
|
|
30
|
-
:
|
|
38
|
+
:splitter, :registered_channels, :localization, :logger, :log_tag,
|
|
39
|
+
:require_all_channels, :data_source
|
|
31
40
|
)
|
|
32
41
|
|
|
33
42
|
def initialize
|
|
34
|
-
@registered_channels ||=
|
|
35
|
-
@splitter ||=
|
|
43
|
+
@registered_channels ||= DEFAULTS[:registered_channels]
|
|
44
|
+
@splitter ||= DEFAULTS[:splitter]
|
|
36
45
|
@registered_receivers = []
|
|
37
|
-
@log_tag ||=
|
|
38
|
-
@localization ||=
|
|
46
|
+
@log_tag ||= DEFAULTS[:log_tag]
|
|
47
|
+
@localization ||= DEFAULTS[:localization]
|
|
48
|
+
@require_all_channels = DEFAULTS[:require_all_channels]
|
|
39
49
|
define_ch_config_methods
|
|
40
50
|
end
|
|
41
51
|
|
|
42
|
-
def collection_file
|
|
43
|
-
@collection_files || raise(
|
|
44
|
-
CollectionFileNotDefined,
|
|
45
|
-
'You must define HeyYou::Config.collection_files'
|
|
46
|
-
)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
52
|
def collection
|
|
50
53
|
@collection ||= load_collection
|
|
51
54
|
end
|
|
@@ -74,6 +77,10 @@ module HeyYou
|
|
|
74
77
|
logger&.info("[#{log_tag}] #{msg} ")
|
|
75
78
|
end
|
|
76
79
|
|
|
80
|
+
def data_source
|
|
81
|
+
DataSource.instance
|
|
82
|
+
end
|
|
83
|
+
|
|
77
84
|
private
|
|
78
85
|
|
|
79
86
|
def define_ch_config_methods
|
|
@@ -91,21 +98,8 @@ module HeyYou
|
|
|
91
98
|
self.class.send(:define_method, ch, method_proc)
|
|
92
99
|
end
|
|
93
100
|
|
|
94
|
-
# Load yaml from collection_file and merge it with yaml from env_collection_file
|
|
95
101
|
def load_collection
|
|
96
|
-
|
|
97
|
-
notification_collection = {}
|
|
98
|
-
collection_files.each do |file|
|
|
99
|
-
notification_collection.merge!(YAML.load_file(file))
|
|
100
|
-
end
|
|
101
|
-
notification_collection.merge!(env_collection)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def load_env_collection
|
|
105
|
-
if env_collection_file
|
|
106
|
-
return YAML.load_file(env_collection_file) rescue { }
|
|
107
|
-
end
|
|
108
|
-
{}
|
|
102
|
+
data_source.load_data
|
|
109
103
|
end
|
|
110
104
|
end
|
|
111
105
|
end
|
|
@@ -11,14 +11,15 @@ module HeyYou
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def configure(&block)
|
|
14
|
-
|
|
15
|
-
@configured ? nil : instance_eval(&block)
|
|
14
|
+
@configured ? raise(AlreadyConfiguredError, 'You already configure HeyYou') : instance_eval(&block)
|
|
16
15
|
@configured = true
|
|
17
16
|
end
|
|
18
17
|
|
|
19
18
|
def config
|
|
20
19
|
@config ||= self.instance
|
|
21
20
|
end
|
|
21
|
+
|
|
22
|
+
class AlreadyConfiguredError < StandardError; end
|
|
22
23
|
end
|
|
23
24
|
end
|
|
24
25
|
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'hey_you/config/conigurable'
|
|
2
|
+
require 'hey_you/data_source/yaml'
|
|
3
|
+
require 'hey_you/data_source/hash'
|
|
4
|
+
|
|
5
|
+
module HeyYou
|
|
6
|
+
class Config
|
|
7
|
+
class DataSource
|
|
8
|
+
extend Configurable
|
|
9
|
+
|
|
10
|
+
attr_accessor :source_class, :options, :source_instance
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@type = DEFAULTS[:type]
|
|
14
|
+
@options = DEFAULTS[:options]
|
|
15
|
+
@source_class = HeyYou::DataSource::Yaml
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def load_data
|
|
19
|
+
return source_instance.load_collections if source_instance
|
|
20
|
+
|
|
21
|
+
if source_class.nil?
|
|
22
|
+
raise InvalidDataSourceError, 'You must pass `config.data_source.source_class` in configuration.'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
source_class.new(options).load_collections
|
|
26
|
+
rescue ArgumentError => err
|
|
27
|
+
problem_fields =
|
|
28
|
+
err.message.gsub(/missing keyword(.?):\s/, '').split(', ').map { |f| "`#{f}`" }.join(', ')
|
|
29
|
+
field_word = problem_fields.split(', ').size > 1 ? 'fields' : 'field'
|
|
30
|
+
msg = "You must pass #{field_word} #{problem_fields} for `config.data_source.options` in configuration"
|
|
31
|
+
|
|
32
|
+
raise InvalidOptionsError, msg
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class InvalidOptionsError < StandardError; end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/hey_you/config/email.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
require 'hey_you/config/conigurable'
|
|
2
2
|
require 'mail'
|
|
3
3
|
|
|
4
4
|
module HeyYou
|
|
@@ -13,7 +13,7 @@ module HeyYou
|
|
|
13
13
|
attr_accessor(
|
|
14
14
|
:from,
|
|
15
15
|
:mail_delivery_method,
|
|
16
|
-
:
|
|
16
|
+
:use_default_mailing,
|
|
17
17
|
:default_delivery_method,
|
|
18
18
|
:default_mailer_class,
|
|
19
19
|
:default_mailer_method
|
|
@@ -21,7 +21,7 @@ module HeyYou
|
|
|
21
21
|
|
|
22
22
|
def initialize
|
|
23
23
|
@mail_delivery_method ||= MAIL_DELIVERY_METHOD
|
|
24
|
-
@
|
|
24
|
+
@use_default_mailing ||= !default_mailer_class.nil?
|
|
25
25
|
@async ||= true
|
|
26
26
|
@default_mailer_method ||= DEFAULT_ACTION_MAILER_METHOD
|
|
27
27
|
@default_delivery_method ||= DEFAULT_DELIVERY_METHOD
|
data/lib/hey_you/config/push.rb
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'hey_you/data_source/_base'
|
|
2
|
+
|
|
3
|
+
module HeyYou
|
|
4
|
+
module DataSource
|
|
5
|
+
class Yaml < Base
|
|
6
|
+
attr_reader :collection_files, :env_collection_file
|
|
7
|
+
|
|
8
|
+
def initialize(collection_files:, env_collection_file: nil)
|
|
9
|
+
@collection_files = collection_files
|
|
10
|
+
@collection_files = [collection_files] if collection_files.is_a?(String)
|
|
11
|
+
@env_collection_file = env_collection_file
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Load yaml from collection_file and merge it with yaml from env_collection_file
|
|
15
|
+
def load_collections
|
|
16
|
+
notification_collection = {}
|
|
17
|
+
collection_files.each do |file|
|
|
18
|
+
notification_collection.merge!(YAML.load_file(file))
|
|
19
|
+
end
|
|
20
|
+
notification_collection.merge!(env_collection)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def env_collection
|
|
24
|
+
@env_collection ||= load_env_collection
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def load_env_collection
|
|
30
|
+
if env_collection_file
|
|
31
|
+
return YAML.load_file(env_collection_file) rescue { }
|
|
32
|
+
end
|
|
33
|
+
{}
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/hey_you/receiver.rb
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
require 'hey_you/sender'
|
|
2
|
+
require 'hey_you/helper'
|
|
2
3
|
|
|
3
4
|
module HeyYou
|
|
4
5
|
module Receiver
|
|
6
|
+
include HeyYou::Helper
|
|
7
|
+
|
|
5
8
|
attr_reader :receiver_channels, :receiver_data
|
|
6
9
|
|
|
7
10
|
def self.extended klass
|
|
@@ -48,7 +51,7 @@ module HeyYou
|
|
|
48
51
|
|
|
49
52
|
@receiver_data = receiver_data
|
|
50
53
|
@receiver_channels = receiver_data.keys
|
|
51
|
-
|
|
54
|
+
config.registrate_receiver(self)
|
|
52
55
|
|
|
53
56
|
define_receive_info_methods
|
|
54
57
|
end
|
|
@@ -57,10 +60,10 @@ module HeyYou
|
|
|
57
60
|
|
|
58
61
|
def check_channels(channels)
|
|
59
62
|
channels.all? do |ch|
|
|
60
|
-
next if
|
|
63
|
+
next if config.registered_channels.include?(ch.to_sym)
|
|
61
64
|
raise(
|
|
62
65
|
NotRegisteredChannel,
|
|
63
|
-
"Channel #{ch} not registered. Registered channels: #{
|
|
66
|
+
"Channel #{ch} not registered. Registered channels: #{config.registered_channels}"
|
|
64
67
|
)
|
|
65
68
|
end
|
|
66
69
|
@received_channels = channels
|
|
@@ -71,18 +74,16 @@ module HeyYou
|
|
|
71
74
|
if receiver_data[ch].is_a?(Hash)
|
|
72
75
|
me = self
|
|
73
76
|
self.send(:define_method, "#{ch}_ch_receive_info", receiver_data[ch].fetch(:subject))
|
|
77
|
+
self.send(:define_method, "#{ch}_ch_receive_condition", receiver_data[ch].fetch(:if, -> { true }))
|
|
74
78
|
self.send(:define_method, "#{ch}_ch_receive_options", -> { me.receiver_data[ch].fetch(:options, {}) })
|
|
75
79
|
else
|
|
76
80
|
self.send(:define_method, "#{ch}_ch_receive_info", receiver_data[ch])
|
|
81
|
+
self.send(:define_method, "#{ch}_ch_receive_condition", -> { true })
|
|
77
82
|
self.send(:define_method, "#{ch}_ch_receive_options", -> { {} })
|
|
78
83
|
end
|
|
79
84
|
end
|
|
80
85
|
end
|
|
81
86
|
|
|
82
|
-
def hey_you_config
|
|
83
|
-
Config.config
|
|
84
|
-
end
|
|
85
|
-
|
|
86
87
|
class NotRegisteredChannel < StandardError;
|
|
87
88
|
end
|
|
88
89
|
end
|
data/lib/hey_you/sender.rb
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
require 'hey_you/helper'
|
|
2
|
+
require 'hey_you/builder'
|
|
3
|
+
require 'hey_you/channels/push'
|
|
4
|
+
require 'hey_you/channels/email'
|
|
5
5
|
|
|
6
6
|
module HeyYou
|
|
7
7
|
class Sender
|
|
8
|
+
include HeyYou::Helper
|
|
9
|
+
extend HeyYou::Helper
|
|
10
|
+
|
|
8
11
|
class << self
|
|
9
12
|
# Send notifications for receiver
|
|
10
13
|
#
|
|
@@ -12,6 +15,7 @@ module HeyYou
|
|
|
12
15
|
# @input notification_key [String] - key for notification builder
|
|
13
16
|
# @input options [Hash]
|
|
14
17
|
# @option only [String/Array[String]] - whitelist for using channels
|
|
18
|
+
# @option force [Boolean] - ignore `if` for receiver
|
|
15
19
|
#
|
|
16
20
|
def send_to(receiver, notification_key, **options)
|
|
17
21
|
unless receiver_valid?(receiver)
|
|
@@ -26,6 +30,10 @@ module HeyYou
|
|
|
26
30
|
def send!(notification_key, receiver, **options)
|
|
27
31
|
to_hash = {}
|
|
28
32
|
receiver.class.receiver_channels.each do |ch|
|
|
33
|
+
if !options[:force] && !receiver.public_send("#{ch}_ch_receive_condition")
|
|
34
|
+
next
|
|
35
|
+
end
|
|
36
|
+
|
|
29
37
|
to_hash[ch] = {
|
|
30
38
|
# Fetch receiver's info for sending: phone_number, email, etc
|
|
31
39
|
subject: receiver.public_send("#{ch}_ch_receive_info"),
|
|
@@ -41,9 +49,9 @@ module HeyYou
|
|
|
41
49
|
builder = Builder.new(notification_key, options)
|
|
42
50
|
response = {}
|
|
43
51
|
config.registered_channels.each do |ch|
|
|
44
|
-
if channel_allowed?(ch, receive_info, builder, options)
|
|
52
|
+
if channel_allowed?(ch, receive_info, builder, options) && builder.respond_to?(ch) && builder.public_send(ch)
|
|
45
53
|
config.log(
|
|
46
|
-
"Send #{ch}-message to
|
|
54
|
+
"Send #{ch}-message to `#{receive_info[ch][:subject]}` with data: #{builder.public_send(ch).data}" \
|
|
47
55
|
" and options: #{receive_info[ch][:options]}"
|
|
48
56
|
)
|
|
49
57
|
receive_options = receive_info[ch].fetch(:options, {}) || {}
|
|
@@ -51,7 +59,7 @@ module HeyYou
|
|
|
51
59
|
builder, to: receive_info[ch][:subject], **receive_options
|
|
52
60
|
)
|
|
53
61
|
else
|
|
54
|
-
config.log("Channel #{ch} not allowed.")
|
|
62
|
+
config.log("Channel #{ch} not allowed or sending condition doesn't return truthy result.")
|
|
55
63
|
end
|
|
56
64
|
end
|
|
57
65
|
response
|
|
@@ -60,9 +68,8 @@ module HeyYou
|
|
|
60
68
|
private
|
|
61
69
|
|
|
62
70
|
def channel_allowed?(ch, to, builder, **options)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
end
|
|
71
|
+
condition = to[ch].is_a?(Hash) ? to[ch.to_sym][:subject] || to[ch.to_s][:subject] : to[ch.to_sym] || to[ch.to_s]
|
|
72
|
+
return false unless condition
|
|
66
73
|
channel_allowed_by_only?(ch, options[:only]) && !builder.send(ch).nil?
|
|
67
74
|
end
|
|
68
75
|
|
|
@@ -75,10 +82,6 @@ module HeyYou
|
|
|
75
82
|
return only.map(&:to_sym).include?(ch.to_sym) if only.is_a?(Array)
|
|
76
83
|
only.to_sym == ch.to_sym
|
|
77
84
|
end
|
|
78
|
-
|
|
79
|
-
def config
|
|
80
|
-
Config.config
|
|
81
|
-
end
|
|
82
85
|
end
|
|
83
86
|
|
|
84
87
|
class NotRegisteredReceiver < StandardError; end
|
data/lib/hey_you/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hey-you
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sergey Nesterov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-07-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: fcm
|
|
@@ -58,14 +58,14 @@ dependencies:
|
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
61
|
+
version: '13.0'
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
68
|
+
version: '13.0'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: rspec
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -121,6 +121,7 @@ files:
|
|
|
121
121
|
- ".rspec"
|
|
122
122
|
- ".rubocop.yml"
|
|
123
123
|
- ".travis.yml"
|
|
124
|
+
- CHANGELOG.md
|
|
124
125
|
- Gemfile
|
|
125
126
|
- README.md
|
|
126
127
|
- Rakefile
|
|
@@ -137,8 +138,13 @@ files:
|
|
|
137
138
|
- lib/hey_you/channels/push.rb
|
|
138
139
|
- lib/hey_you/config.rb
|
|
139
140
|
- lib/hey_you/config/conigurable.rb
|
|
141
|
+
- lib/hey_you/config/data_source.rb
|
|
140
142
|
- lib/hey_you/config/email.rb
|
|
141
143
|
- lib/hey_you/config/push.rb
|
|
144
|
+
- lib/hey_you/data_source/_base.rb
|
|
145
|
+
- lib/hey_you/data_source/hash.rb
|
|
146
|
+
- lib/hey_you/data_source/yaml.rb
|
|
147
|
+
- lib/hey_you/helper.rb
|
|
142
148
|
- lib/hey_you/receiver.rb
|
|
143
149
|
- lib/hey_you/sender.rb
|
|
144
150
|
- lib/hey_you/version.rb
|
|
@@ -160,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
160
166
|
- !ruby/object:Gem::Version
|
|
161
167
|
version: '0'
|
|
162
168
|
requirements: []
|
|
163
|
-
rubygems_version: 3.0.
|
|
169
|
+
rubygems_version: 3.0.3
|
|
164
170
|
signing_key:
|
|
165
171
|
specification_version: 4
|
|
166
172
|
summary: Send multichannel notification with one command.
|