notification-settings 1.2.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NotificationSettings
4
- require 'notification_settings/configuration'
4
+ require_relative 'notification_settings/configuration'
5
5
 
6
- require 'notification_settings/engine'
6
+ require_relative 'notification_settings/engine'
7
7
 
8
8
  autoload :Target, 'notification_settings/target'
9
9
  autoload :Subscriber, 'notification_settings/subscriber'
10
10
  autoload :Subscribable, 'notification_settings/subscribable'
11
- autoload :SettingLibrary, 'notification_settings/setting_library'
12
- autoload :SubscriptionLibrary, 'notification_settings/subscription_library'
13
- autoload :NotificationLibrary, 'notification_settings/notification_library'
11
+ autoload :Settings, 'notification_settings/settings'
12
+ autoload :Status, 'notification_settings/status'
13
+ autoload :NotificationLib, 'notification_settings/notification_lib'
14
14
  autoload :NotificationScopes, 'notification_settings/notification_scopes'
15
+ autoload :CategoryPreferencesForm,
16
+ 'notification_settings/category_preferences_form'
17
+ autoload :DeliveryMethodPreferencesForm,
18
+ 'notification_settings/delivery_method_preferences_form'
19
+ autoload :PreferencesForm, 'notification_settings/preferences_form'
15
20
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model'
4
+
5
+ module NotificationSettings
6
+ class CategoryPreferencesForm
7
+ include ActiveModel::Model
8
+
9
+ NotificationSettings.configuration.categories.each do |category|
10
+ attribute category, :boolean, default: true
11
+ end
12
+ end
13
+ end
@@ -2,29 +2,37 @@
2
2
 
3
3
  module NotificationSettings
4
4
  class << self
5
- attr_accessor :configuration
5
+ attr_writer :configuration
6
+
7
+ def configuration
8
+ @configuration ||= Configuration.new
9
+ end
6
10
  end
7
11
 
8
12
  def self.configure
9
- self.configuration ||= Configuration.new
10
13
  yield configuration
11
14
  end
12
15
 
13
16
  class Configuration
17
+ attr_accessor :categories
14
18
  attr_accessor :default_category
15
19
  attr_accessor :last_seen
16
20
  attr_accessor :idle_after
17
21
  attr_accessor :offline_after
22
+ attr_accessor :statuses
18
23
  attr_accessor :do_not_notify_statuses
19
- attr_accessor :do_not_push_statuses
24
+ attr_accessor :do_not_deliver_statuses
20
25
 
21
26
  def initialize
22
- @default_category = 'notification'
23
- @last_seen = 'last_seen'
27
+ @categories = [:notification]
28
+ @default_category = :notification
29
+ @last_seen = :last_seen
24
30
  @idle_after = 10.minutes
25
31
  @offline_after = 3.hours
26
- @do_not_notify_statuses = []
27
- @do_not_push_statuses = ['do not disturb']
32
+ @statuses = ['online', 'idle', 'offline', 'do not notify',
33
+ 'do not disturb']
34
+ @do_not_notify_statuses = ['do not notify']
35
+ @do_not_deliver_statuses = ['do not disturb']
28
36
  end
29
37
  end
30
38
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model'
4
+
5
+ module NotificationSettings
6
+ class DeliveryMethodPreferencesForm
7
+ include ActiveModel::Model
8
+
9
+ attribute :enabled, :boolean, default: true
10
+ NotificationPusher.configuration.delivery_methods
11
+ .each do |delivery_method, _|
12
+ attribute delivery_method, :boolean, default: true
13
+ end
14
+ end
15
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails/railtie'
3
+ require 'rails/engine'
4
4
  require 'active_record'
5
5
 
6
6
  module NotificationSettings
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'notification-handler'
4
+ require 'active_support'
5
+
6
+ module NotificationSettings
7
+ module NotificationLib
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ before_create :validate_create
12
+
13
+ validates :category, inclusion: {
14
+ in: NotificationSettings.configuration.categories + [nil]
15
+ }
16
+
17
+ belongs_to :subscription,
18
+ class_name: 'NotificationSettings::Subscription',
19
+ optional: true
20
+
21
+ include NotificationSettings::NotificationLib::InstanceMethods
22
+ end
23
+
24
+ # rubocop:disable Metrics/ModuleLength
25
+ module InstanceMethods
26
+ def category
27
+ self[:category] || NotificationSettings.configuration.default_category
28
+ end
29
+
30
+ def deliver(delivery_methods, delivery_options = {})
31
+ return false unless delivery_allowed?(delivery_methods)
32
+
33
+ super
34
+ end
35
+
36
+ def creation_allowed?
37
+ status_allows_creation? &&
38
+ settings_allow_creation? &&
39
+ category_settings_allow_creation?
40
+ end
41
+
42
+ # delivery_methods may be an array or a single value
43
+ def delivery_allowed?(delivery_methods)
44
+ creation_allowed? &&
45
+ status_allows_delivery? &&
46
+ delivery_methods_allowed?(Array(delivery_methods))
47
+ end
48
+
49
+ private
50
+
51
+ def validate_create
52
+ throw(:abort) unless creation_allowed?
53
+ end
54
+
55
+ def status_allows_creation?
56
+ !do_not_notify_statuses.include?(target.status)
57
+ end
58
+
59
+ def settings_allow_creation?
60
+ target.settings.fetch(:enabled, true) &&
61
+ (subscription.nil? || subscription.settings.fetch(:enabled, true))
62
+ end
63
+
64
+ def category_settings_allow_creation?
65
+ category_settings(target, category).fetch(:enabled, true) &&
66
+ (subscription.nil? ||
67
+ category_settings(subscription, category).fetch(:enabled, true))
68
+ end
69
+
70
+ def delivery_methods_allowed?(delivery_methods)
71
+ delivery_methods.any? do |delivery_method|
72
+ delivery_method_allowed?(delivery_method)
73
+ end
74
+ end
75
+
76
+ def delivery_method_allowed?(delivery_method)
77
+ settings_allow_delivery?(delivery_method) &&
78
+ category_settings_allow_delivery?(delivery_method)
79
+ end
80
+
81
+ def status_allows_delivery?
82
+ !do_not_deliver_statuses.include?(target.status)
83
+ end
84
+
85
+ def settings_allow_delivery?(delivery_method)
86
+ if local_delivery_method_setting?(delivery_method)
87
+ local_settings_allow_delivery?(delivery_method)
88
+ else
89
+ global_settings_allow_delivery?
90
+ end
91
+ end
92
+
93
+ def local_delivery_method_setting?(delivery_method)
94
+ !local_delivery_method_setting(delivery_method).nil?
95
+ end
96
+
97
+ def local_settings_allow_delivery?(delivery_method)
98
+ local_delivery_method_setting(delivery_method, true)
99
+ end
100
+
101
+ def local_delivery_method_setting(delivery_method, default = nil)
102
+ delivery_method_setting(target, delivery_method, default) &&
103
+ (subscription.nil? ||
104
+ delivery_method_setting(subscription, delivery_method, default))
105
+ end
106
+
107
+ def global_settings_allow_delivery?
108
+ delivery_method_setting(target, :enabled, true) &&
109
+ (subscription.nil? ||
110
+ delivery_method_setting(subscription, :enabled, true))
111
+ end
112
+
113
+ def category_settings_allow_delivery?(delivery_method)
114
+ if local_delivery_method_category_setting?(delivery_method)
115
+ local_category_settings_allow_delivery?(delivery_method)
116
+ else
117
+ global_category_settings_allow_delivery?
118
+ end
119
+ end
120
+
121
+ def local_delivery_method_category_setting?(delivery_method)
122
+ !local_delivery_method_category_setting(delivery_method).nil?
123
+ end
124
+
125
+ def local_category_settings_allow_delivery?(delivery_method)
126
+ local_delivery_method_category_setting(delivery_method, true)
127
+ end
128
+
129
+ def local_delivery_method_category_setting(delivery_method, default = nil)
130
+ category_delivery_method_setting(target, category, delivery_method,
131
+ default) &&
132
+ (subscription.nil? ||
133
+ category_delivery_method_setting(subscription, category,
134
+ delivery_method, default))
135
+ end
136
+
137
+ def global_category_settings_allow_delivery?
138
+ category_delivery_method_setting(target, category, :enabled, true) &&
139
+ (subscription.nil? ||
140
+ category_delivery_method_setting(subscription, category, :enabled,
141
+ true))
142
+ end
143
+
144
+ def delivery_method_setting(object, delivery_method, default)
145
+ object.settings.delivery_methods_.fetch(delivery_method.to_s, default)
146
+ end
147
+
148
+ def category_settings(object, category)
149
+ object.settings.categories_.send("#{category}_")
150
+ end
151
+
152
+ def category_delivery_method_setting(object, category, delivery_method,
153
+ default)
154
+ category_settings(object, category).delivery_methods_
155
+ .fetch(delivery_method.to_s, default)
156
+ end
157
+
158
+ def do_not_notify_statuses
159
+ NotificationSettings.configuration.do_not_notify_statuses
160
+ end
161
+
162
+ def do_not_deliver_statuses
163
+ NotificationSettings.configuration.do_not_deliver_statuses
164
+ end
165
+ end
166
+ # rubocop:enable Metrics/ModuleLength
167
+ end
168
+ end
@@ -7,11 +7,7 @@ module NotificationSettings
7
7
  module NotificationScopes
8
8
  extend ActiveSupport::Concern
9
9
 
10
- included do
11
- include NotificationSettings::NotificationScopes::InstanceMethods
12
- end
13
-
14
- module InstanceMethods
10
+ module ClassMethods
15
11
  def method_missing(method, *args)
16
12
  if method.to_s[/(.+)_category/]
17
13
  where(category: $1.singularize.classify)
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model'
4
+
5
+ module NotificationSettings
6
+ class PreferencesForm
7
+ include ActiveModel::Model
8
+
9
+ attribute :enabled, :boolean, default: true
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'hashie'
5
+
6
+ module NotificationSettings
7
+ module Settings
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ before_validation :build_settings
12
+
13
+ serialize :settings, Hashie::Mash
14
+
15
+ include NotificationSettings::Settings::InstanceMethods
16
+ end
17
+
18
+ module InstanceMethods
19
+ private
20
+
21
+ def build_settings
22
+ return if settings.present? && settings.is_a?(Hashie::Mash)
23
+
24
+ self.settings = Hashie::Mash.new
25
+ end
26
+ end
27
+ end
28
+ end
@@ -3,27 +3,33 @@
3
3
  require 'active_support'
4
4
 
5
5
  module NotificationSettings
6
- module SettingLibrary
6
+ module Status
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- include NotificationSettings::SettingLibrary::InstanceMethods
10
+ validates :status,
11
+ inclusion: { in: NotificationSettings.configuration.statuses }
12
+
13
+ include NotificationSettings::Status::InstanceMethods
11
14
  end
12
15
 
13
16
  module InstanceMethods
14
17
  def status
18
+ self[:status] || default_status
19
+ end
20
+
21
+ private
22
+
23
+ def default_status
15
24
  if idle? && !offline?
16
- default = 'idle'
25
+ 'idle'
17
26
  elsif offline?
18
- default = 'offline'
27
+ 'offline'
19
28
  else
20
29
  'online'
21
30
  end
22
- self[:status] || default
23
31
  end
24
32
 
25
- private
26
-
27
33
  def idle?
28
34
  return unless time_since_last_seen_round
29
35
 
@@ -41,11 +47,9 @@ module NotificationSettings
41
47
  end
42
48
 
43
49
  def time_since_last_seen
44
- return unless object.respond_to?(
45
- NotificationSettings.configuration.last_seen
46
- )
50
+ return unless respond_to?(NotificationSettings.configuration.last_seen)
47
51
 
48
- Time.now - object.send(NotificationSettings.configuration.last_seen)
52
+ Time.now - send(NotificationSettings.configuration.last_seen)
49
53
  end
50
54
 
51
55
  def idle_after
@@ -7,12 +7,10 @@ module NotificationSettings
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- has_many :notification_subscriptions,
10
+ has_many :notification_subscribers,
11
11
  as: :subscribable,
12
12
  class_name: 'NotificationSettings::Subscription',
13
13
  dependent: :destroy
14
- has_many :notification_subscribers,
15
- through: :notification_subscriptions, source: :subscriber
16
14
 
17
15
  include NotificationSettings::Subscribable::InstanceMethods
18
16
  end
@@ -20,24 +18,24 @@ module NotificationSettings
20
18
  module InstanceMethods
21
19
  def notify_subscribers(options = {})
22
20
  options[:object] = self
23
- subscribers = notify_dependents(options.delete(:dependents))
24
- notification_subscribers&.each do |subscriber|
25
- subscribers << subscriber
21
+ subscriptions = notify_dependents(options.delete(:dependents))
22
+ notification_subscribers&.each do |subscription|
23
+ subscriptions << subscription
26
24
  end
27
- subscribers.to_a.uniq&.each do |subscriber|
28
- subscriber.notify(options)
25
+ subscriptions.to_a.uniq&.each do |subscription|
26
+ subscription.subscriber.notify(options)
29
27
  end
30
28
  end
31
29
 
32
30
  def notify_dependents(dependents)
33
- subscribers = []
31
+ subscriptions = []
34
32
  dependents ||= notification_dependents
35
33
  dependents&.each do |dependent|
36
- dependent.notification_subscribers&.each do |subscriber|
37
- subscribers << subscriber
34
+ dependent.notification_subscribers&.each do |subscription|
35
+ subscriptions << subscription
38
36
  end
39
37
  end
40
- subscribers
38
+ subscriptions
41
39
  end
42
40
 
43
41
  private
@@ -7,28 +7,27 @@ module NotificationSettings
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- has_many :notification_subscriptions,
10
+ has_many :notification_subscribables,
11
11
  as: :subscriber,
12
12
  class_name: 'NotificationSettings::Subscription',
13
13
  dependent: :destroy
14
- has_many :notification_subscribables,
15
- through: :notification_subscriptions, source: :subscribable
16
14
 
17
15
  include NotificationSettings::Subscriber::InstanceMethods
18
16
  end
19
17
 
20
18
  module InstanceMethods
21
19
  def subscribe(subscribable, options = {})
22
- options[:subscribable] = subscribable
23
- notification_subscriptions.create(options)
20
+ notification_subscribables.create(
21
+ options.merge(subscribable: subscribable)
22
+ )
24
23
  end
25
24
 
26
25
  def unsubscribe(subscribable)
27
- subscription = notification_subscriptions.find_by(
26
+ subscription = notification_subscribables.find_by(
28
27
  subscribable_id: subscribable.id,
29
28
  subscribable_type: subscribable.class.name
30
29
  )
31
- subscription.destroy
30
+ subscription&.destroy
32
31
  end
33
32
  end
34
33
  end