hey-you 0.1.8 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 111d968c94f6f51e803d4232f32e335be19897f91d0ab391ce46a85916a3eae0
4
- data.tar.gz: 9915bfd76064d7c977fab321aa655e66dfb32a4b18a9303b7529c8c115bc991c
3
+ metadata.gz: 755f8775f2918592a3faf297f7dbed8f5b7253d137ac47ffedae9a9106a5d44f
4
+ data.tar.gz: 17c927968d8fe27c6a5e8b2ace86af1bb30683f3cc968099aca19401c94cbcd7
5
5
  SHA512:
6
- metadata.gz: c31b6441abb8c789a634857200271d92a2f685bc1f4e85c636c13b616d5ddccb30e876dbf2318dfcb2b484cf715ed57bca6bff137bccb5934d09b263d846333b
7
- data.tar.gz: 54138ca7c7d4f13b6c226273d1fa85d31b9fda63426c3f67f9c20071f71cee2990403ae7d5f7257bfe2cc19053494c498333914bdb370a7bc87375eef521445b
6
+ metadata.gz: 592e4f17b2e26f26f04477150118a91d2cf68696bc17f3021617e554a14bddb19fd3fec5e2c8d2dc37342d045e6ca2c2c679969de645aa9269edf6cc139ea596
7
+ data.tar.gz: 83aa1a371cffa0efce33fb69e410abbe6d0eda85e019ab117f1e1ccb93cfee8d7ce92fb4b23d83a4b19d08615ccc0616c378ebd030801bc10b0773edb71e1596
@@ -1,10 +1,9 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.3.3
5
- - 2.4.2
6
- - 2.5.3
7
- - 2.6.1
4
+ - 2.5.0
5
+ - 2.6.0
6
+ - 2.7.0
8
7
  before_install: gem install bundler
9
8
  scripts:
10
9
  - bundle exec rspec
@@ -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 [Alpha]
1
+ # HeyYou
2
2
  [![Build Status](https://travis-ci.com/QNester/hey-you.svg?branch=master)](https://travis-ci.com/QNester/hey-you#)
3
+ [![Gem Version](https://badge.fury.io/rb/hey-you.svg)](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.3.0 min (rspec works with ruby 2.3.3, 2.4.2, 2.5.3)
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.collection_files = ['config/notifications.yml']
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
- ##### Base
54
- * __config.collection_files__ - File or files contained all your notifications texts.
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
- config.collection_files = I18n.available_locales.map { |locale| "config/notifications/#{locale}.yml" }
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.default_mailing__ - use default mail sending or use custom mailer classes
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: { subject: -> { email }, options: { mailer_class: UserMailer, mailer_method: :notify! } }
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
- You need create yml file with follow format:
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
  [![Gem Version](https://badge.fury.io/rb/hey-you-slack.svg)](https://badge.fury.io/rb/hey-you-slack)
364
426
 
365
427
  ## Development
@@ -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", '~> 10.5'
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'
@@ -1,31 +1,51 @@
1
1
  require 'i18n'
2
- require_relative 'builder/email'
3
- require_relative 'builder/push'
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
- attr_reader :data, :options
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
- ch_builder =
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 define_ch_method(ch)
28
- method_proc = -> { instance_variable_get("@#{ch}".to_sym) }
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 config
46
- Config.config
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
@@ -12,6 +12,10 @@ module HeyYou
12
12
  @body = interpolate(ch_data.fetch('body'), options)
13
13
  @subject = interpolate(ch_data.fetch('subject'), options)
14
14
  end
15
+
16
+ def to_hash
17
+ { body: body, subject: subject }
18
+ end
15
19
  end
16
20
  end
17
21
  end
@@ -10,6 +10,10 @@ module HeyYou
10
10
  @body = interpolate(ch_data.fetch('body'), options)
11
11
  @data = options[:data] || {}
12
12
  end
13
+
14
+ def to_hash
15
+ { title: title, body: body, data: data }
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -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
- raise CredentialsNotExists unless credentials_present?
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
- class CredentialsNotExists < StandardError;
80
- end
81
- class ActionMailerClassNotDefined < StandardError;
82
- end
83
- class MailerClassNotDefined < StandardError;
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
@@ -1,7 +1,8 @@
1
1
  require 'yaml'
2
- require_relative 'config/conigurable'
3
- require_relative 'config/push'
4
- require_relative 'config/email'
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
- DEFAULT_REGISTERED_CHANNELS = %i[email push]
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
- :collection_files, :env_collection_file, :splitter,
30
- :registered_channels, :localization, :logger, :log_tag
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 ||= DEFAULT_REGISTERED_CHANNELS
35
- @splitter ||= DEFAULT_SPLITTER
43
+ @registered_channels ||= DEFAULTS[:registered_channels]
44
+ @splitter ||= DEFAULTS[:splitter]
36
45
  @registered_receivers = []
37
- @log_tag ||= DEFAULT_GLOBAL_LOG_TAG
38
- @localization ||= DEFAULT_LOCALIZATION_FLAG
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
- @collection_files = [collection_files] if collection_files.is_a?(String)
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
- # TODO: log warn "Already configured" instead nil
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
@@ -1,4 +1,4 @@
1
- require_relative 'conigurable'
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
- :default_mailing,
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
- @default_mailing ||= !default_mailer_class.nil?
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
@@ -1,4 +1,4 @@
1
- require_relative 'conigurable'
1
+ require 'hey_you/config/conigurable'
2
2
  require 'fcm'
3
3
 
4
4
  module HeyYou
@@ -0,0 +1,9 @@
1
+ module HeyYou
2
+ module DataSource
3
+ class Base
4
+ def load_notifications
5
+ raise NotImplementedError
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ require 'hey_you/data_source/_base'
2
+
3
+ module HeyYou
4
+ module DataSource
5
+ class Hash < Base
6
+ attr_reader :data
7
+
8
+ def initialize(data:)
9
+ @data = data
10
+ end
11
+
12
+ def load_collections
13
+ data
14
+ end
15
+ end
16
+ end
17
+ end
@@ -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
@@ -0,0 +1,7 @@
1
+ module HeyYou
2
+ module Helper
3
+ def config
4
+ Config.instance
5
+ end
6
+ end
7
+ end
@@ -1,7 +1,10 @@
1
- require_relative 'sender'
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
- hey_you_config.registrate_receiver(self)
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 hey_you_config.registered_channels.include?(ch.to_sym)
63
+ next if config.registered_channels.include?(ch.to_sym)
61
64
  raise(
62
65
  NotRegisteredChannel,
63
- "Channel #{ch} not registered. Registered channels: #{hey_you_config.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
@@ -1,10 +1,13 @@
1
- require_relative 'builder'
2
-
3
- require_relative 'channels/push'
4
- require_relative 'channels/email'
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 #{receive_info[ch][:subject]} with data: #{builder.send(ch).data}" \
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
- unless to[ch].is_a?(Hash) ? to[ch.to_sym][:subject] || to[ch.to_s][:subject] : to[ch.to_sym] || to[ch.to_s]
64
- return false
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
@@ -1,3 +1,3 @@
1
1
  module HeyYou
2
- VERSION = "0.1.8"
2
+ VERSION = "1.2.2"
3
3
  end
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: 0.1.8
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: 2019-04-28 00:00:00.000000000 Z
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: '10.5'
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: '10.5'
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.1
169
+ rubygems_version: 3.0.3
164
170
  signing_key:
165
171
  specification_version: 4
166
172
  summary: Send multichannel notification with one command.