noticed 1.6.3 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +269 -237
  3. data/app/jobs/noticed/application_job.rb +9 -0
  4. data/app/jobs/noticed/event_job.rb +19 -0
  5. data/app/models/concerns/noticed/deliverable.rb +115 -0
  6. data/app/models/concerns/noticed/notification_methods.rb +17 -0
  7. data/app/models/concerns/noticed/readable.rb +78 -0
  8. data/app/models/noticed/application_record.rb +6 -0
  9. data/app/models/noticed/deliverable/deliver_by.rb +43 -0
  10. data/app/models/noticed/event.rb +15 -0
  11. data/app/models/noticed/notification.rb +14 -0
  12. data/db/migrate/20231215190233_create_noticed_tables.rb +25 -0
  13. data/lib/generators/noticed/delivery_method_generator.rb +1 -1
  14. data/lib/generators/noticed/install_generator.rb +19 -0
  15. data/lib/generators/noticed/{notification_generator.rb → notifier_generator.rb} +2 -2
  16. data/lib/generators/noticed/templates/README +5 -4
  17. data/lib/generators/noticed/templates/delivery_method.rb.tt +4 -8
  18. data/lib/generators/noticed/templates/notifier.rb.tt +24 -0
  19. data/lib/noticed/api_client.rb +44 -0
  20. data/lib/noticed/bulk_delivery_method.rb +46 -0
  21. data/lib/noticed/bulk_delivery_methods/discord.rb +11 -0
  22. data/lib/noticed/bulk_delivery_methods/slack.rb +17 -0
  23. data/lib/noticed/bulk_delivery_methods/webhook.rb +18 -0
  24. data/lib/noticed/coder.rb +2 -0
  25. data/lib/noticed/delivery_method.rb +51 -0
  26. data/lib/noticed/delivery_methods/action_cable.rb +7 -39
  27. data/lib/noticed/delivery_methods/discord.rb +11 -0
  28. data/lib/noticed/delivery_methods/email.rb +13 -45
  29. data/lib/noticed/delivery_methods/fcm.rb +23 -64
  30. data/lib/noticed/delivery_methods/ios.rb +25 -112
  31. data/lib/noticed/delivery_methods/microsoft_teams.rb +5 -22
  32. data/lib/noticed/delivery_methods/slack.rb +6 -16
  33. data/lib/noticed/delivery_methods/test.rb +2 -12
  34. data/lib/noticed/delivery_methods/twilio_messaging.rb +37 -0
  35. data/lib/noticed/delivery_methods/vonage_sms.rb +20 -0
  36. data/lib/noticed/delivery_methods/webhook.rb +17 -0
  37. data/lib/noticed/engine.rb +1 -9
  38. data/lib/noticed/required_options.rb +21 -0
  39. data/lib/noticed/translation.rb +7 -3
  40. data/lib/noticed/version.rb +1 -1
  41. data/lib/noticed.rb +30 -15
  42. metadata +29 -40
  43. data/lib/generators/noticed/model/base_generator.rb +0 -47
  44. data/lib/generators/noticed/model/mysql_generator.rb +0 -18
  45. data/lib/generators/noticed/model/postgresql_generator.rb +0 -18
  46. data/lib/generators/noticed/model/sqlite3_generator.rb +0 -18
  47. data/lib/generators/noticed/model_generator.rb +0 -63
  48. data/lib/generators/noticed/templates/notification.rb.tt +0 -27
  49. data/lib/noticed/base.rb +0 -160
  50. data/lib/noticed/delivery_methods/base.rb +0 -95
  51. data/lib/noticed/delivery_methods/database.rb +0 -34
  52. data/lib/noticed/delivery_methods/twilio.rb +0 -51
  53. data/lib/noticed/delivery_methods/vonage.rb +0 -40
  54. data/lib/noticed/has_notifications.rb +0 -49
  55. data/lib/noticed/model.rb +0 -85
  56. data/lib/noticed/notification_channel.rb +0 -15
  57. data/lib/noticed/text_coder.rb +0 -16
  58. data/lib/rails_6_polyfills/actioncable/test_adapter.rb +0 -70
  59. data/lib/rails_6_polyfills/actioncable/test_helper.rb +0 -143
  60. data/lib/rails_6_polyfills/activejob/serializers.rb +0 -240
  61. data/lib/rails_6_polyfills/base.rb +0 -18
  62. data/lib/tasks/noticed_tasks.rake +0 -4
@@ -0,0 +1,9 @@
1
+ module Noticed
2
+ class ApplicationJob < ActiveJob::Base
3
+ # Automatically retry jobs that encountered a deadlock
4
+ # retry_on ActiveRecord::Deadlocked
5
+
6
+ # Most jobs are safe to ignore if the underlying records are no longer available
7
+ discard_on ActiveJob::DeserializationError
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ module Noticed
2
+ class EventJob < ApplicationJob
3
+ queue_as :default
4
+
5
+ def perform(event)
6
+ # Enqueue bulk deliveries
7
+ event.bulk_delivery_methods.each do |_, deliver_by|
8
+ deliver_by.perform_later(event)
9
+ end
10
+
11
+ # Enqueue individual deliveries
12
+ event.notifications.each do |notification|
13
+ event.delivery_methods.each do |_, deliver_by|
14
+ deliver_by.perform_later(notification)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,115 @@
1
+ module Noticed
2
+ module Deliverable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class_attribute :bulk_delivery_methods, instance_writer: false, default: {}
7
+ class_attribute :delivery_methods, instance_writer: false, default: {}
8
+ class_attribute :required_param_names, instance_writer: false, default: []
9
+
10
+ attribute :params, default: {}
11
+
12
+ if Rails.gem_version >= Gem::Version.new("7.1.0.alpha")
13
+ serialize :params, coder: Coder
14
+ else
15
+ serialize :params, Coder
16
+ end
17
+ end
18
+
19
+ class_methods do
20
+ def inherited(base)
21
+ base.bulk_delivery_methods = bulk_delivery_methods.dup
22
+ base.delivery_methods = delivery_methods.dup
23
+ base.required_param_names = required_param_names.dup
24
+ super
25
+ end
26
+
27
+ def bulk_deliver_by(name, options = {})
28
+ raise NameError, "#{name} has already been used for this Notifier." if bulk_delivery_methods.has_key?(name)
29
+
30
+ config = ActiveSupport::OrderedOptions.new.merge(options)
31
+ yield config if block_given?
32
+ bulk_delivery_methods[name] = DeliverBy.new(name, config, bulk: true)
33
+ end
34
+
35
+ def deliver_by(name, options = {})
36
+ raise NameError, "#{name} has already been used for this Notifier." if delivery_methods.has_key?(name)
37
+
38
+ config = ActiveSupport::OrderedOptions.new.merge(options)
39
+ yield config if block_given?
40
+ delivery_methods[name] = DeliverBy.new(name, config)
41
+ end
42
+
43
+ def required_params(*names)
44
+ required_param_names.concat names
45
+ end
46
+ alias_method :required_param, :required_params
47
+
48
+ def with(params)
49
+ record = params.delete(:record)
50
+ new(params: params, record: record)
51
+ end
52
+
53
+ def deliver(recipients = nil, options = {})
54
+ new.deliver(recipients, options)
55
+ end
56
+ end
57
+
58
+ # CommentNotifier.deliver(User.all)
59
+ # CommentNotifier.deliver(User.all, priority: 10)
60
+ # CommentNotifier.deliver(User.all, queue: :low_priority)
61
+ # CommentNotifier.deliver(User.all, wait: 5.minutes)
62
+ # CommentNotifier.deliver(User.all, wait_until: 1.hour.from_now)
63
+ def deliver(recipients = nil, options = {})
64
+ validate!
65
+
66
+ transaction do
67
+ save!
68
+
69
+ recipients_attributes = Array.wrap(recipients).map do |recipient|
70
+ recipient_attributes_for(recipient)
71
+ end
72
+
73
+ if Rails.gem_version >= Gem::Version.new("7.0.0.alpha1")
74
+ notifications.insert_all!(recipients_attributes, record_timestamps: true) if recipients_attributes.any?
75
+ else
76
+ time = Time.current
77
+ recipients_attributes.each do |attributes|
78
+ attributes[:created_at] = time
79
+ attributes[:updated_at] = time
80
+ end
81
+ notifications.insert_all!(recipients_attributes) if recipients_attributes.any?
82
+ end
83
+ end
84
+
85
+ # Enqueue delivery job
86
+ EventJob.set(options).perform_later(self)
87
+
88
+ self
89
+ end
90
+
91
+ def recipient_attributes_for(recipient)
92
+ {
93
+ type: "#{self.class.name}::Notification",
94
+ recipient_type: recipient.class.name,
95
+ recipient_id: recipient.id
96
+ }
97
+ end
98
+
99
+ def validate!
100
+ validate_params!
101
+ validate_delivery_methods!
102
+ end
103
+
104
+ def validate_params!
105
+ required_param_names.each do |param_name|
106
+ raise ValidationError, "Param `#{param_name}` is required for #{self.class.name}." unless params[param_name].present?
107
+ end
108
+ end
109
+
110
+ def validate_delivery_methods!
111
+ bulk_delivery_methods.values.each(&:validate!)
112
+ delivery_methods.values.each(&:validate!)
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,17 @@
1
+ module Noticed
2
+ module NotificationMethods
3
+ extend ActiveSupport::Concern
4
+
5
+ class_methods do
6
+ # Generate a Notification class each time a Notifier is defined
7
+ def inherited(notifier)
8
+ super
9
+ notifier.const_set :Notification, Class.new(Noticed::Notification)
10
+ end
11
+
12
+ def notification_methods(&block)
13
+ const_get(:Notification).class_eval(&block)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,78 @@
1
+ module Noticed
2
+ module Readable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ scope :read, -> { where.not(read_at: nil) }
7
+ scope :unread, -> { where(read_at: nil) }
8
+ scope :seen, -> { where.not(seen_at: nil) }
9
+ scope :unseen, -> { where(seen_at: nil) }
10
+ end
11
+
12
+ class_methods do
13
+ def mark_as_read
14
+ update_all(read_at: Time.current)
15
+ end
16
+
17
+ def mark_as_unread
18
+ update_all(read_at: nil)
19
+ end
20
+
21
+ def mark_as_seen
22
+ update_all(seen_at: Time.current)
23
+ end
24
+
25
+ def mark_as_unseen
26
+ update_all(seen_at: nil)
27
+ end
28
+ end
29
+
30
+ def mark_as_read
31
+ update(read_at: Time.current)
32
+ end
33
+
34
+ def mark_as_read!
35
+ update!(read_at: Time.current)
36
+ end
37
+
38
+ def mark_as_unread
39
+ update(read_at: nil)
40
+ end
41
+
42
+ def mark_as_unread!
43
+ update!(read_at: nil)
44
+ end
45
+
46
+ def mark_as_seen
47
+ update(seen_at: Time.current)
48
+ end
49
+
50
+ def mark_as_seen!
51
+ update!(seen_at: Time.current)
52
+ end
53
+
54
+ def mark_as_unseen
55
+ update(seen_at: nil)
56
+ end
57
+
58
+ def mark_as_unseen!
59
+ update!(seen_at: nil)
60
+ end
61
+
62
+ def read?
63
+ read_at?
64
+ end
65
+
66
+ def unread?
67
+ !read_at?
68
+ end
69
+
70
+ def seen?
71
+ seen_at?
72
+ end
73
+
74
+ def unseen?
75
+ !seen_at?
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,6 @@
1
+ module Noticed
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ self.table_name_prefix = "noticed_"
5
+ end
6
+ end
@@ -0,0 +1,43 @@
1
+ module Noticed
2
+ module Deliverable
3
+ class DeliverBy
4
+ attr_reader :name, :config, :bulk
5
+
6
+ def initialize(name, config, bulk: false)
7
+ @name, @config, @bulk, = name, config, bulk
8
+ end
9
+
10
+ def constant
11
+ namespace = bulk ? "Noticed::BulkDeliveryMethods" : "Noticed::DeliveryMethods"
12
+ config.fetch(:class, [namespace, name.to_s.camelize].join("::")).constantize
13
+ end
14
+
15
+ def validate!
16
+ constant.required_option_names.each do |option|
17
+ raise ValidationError, "option `#{option}` must be set for `deliver_by :#{name}`" unless config[option].present?
18
+ end
19
+ end
20
+
21
+ def perform_later(event_or_notification, options = {})
22
+ options[:wait] = evaluate_option(:wait, event_or_notification) if config.has_key?(:wait)
23
+ options[:wait_until] = evaluate_option(:wait_until, event_or_notification) if config.has_key?(:wait_until)
24
+ options[:queue] = evaluate_option(:queue, event_or_notification) if config.has_key?(:queue)
25
+ options[:priority] = evaluate_option(:priority, event_or_notification) if config.has_key?(:priority)
26
+
27
+ constant.set(options).perform_later(name, event_or_notification)
28
+ end
29
+
30
+ def evaluate_option(name, context)
31
+ option = config[name]
32
+
33
+ if option&.respond_to?(:call)
34
+ context.instance_exec(&option)
35
+ elsif option.is_a?(Symbol) && context.respond_to?(option)
36
+ context.send(option)
37
+ else
38
+ option
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ module Noticed
2
+ class Event < ApplicationRecord
3
+ include Deliverable
4
+ include NotificationMethods
5
+ include Translation
6
+ include Rails.application.routes.url_helpers
7
+
8
+ belongs_to :record, polymorphic: true, optional: true
9
+ has_many :notifications, dependent: :delete_all
10
+
11
+ accepts_nested_attributes_for :notifications
12
+
13
+ scope :newest_first, -> { order(created_at: :desc) }
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module Noticed
2
+ class Notification < ApplicationRecord
3
+ include Rails.application.routes.url_helpers
4
+ include Readable
5
+ include Translation
6
+
7
+ belongs_to :event
8
+ belongs_to :recipient, polymorphic: true
9
+
10
+ scope :newest_first, -> { order(created_at: :desc) }
11
+
12
+ delegate :params, :record, to: :event
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ class CreateNoticedTables < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :noticed_events do |t|
4
+ t.string :type
5
+ t.belongs_to :record, polymorphic: true
6
+ if t.respond_to?(:jsonb)
7
+ t.jsonb :params
8
+ else
9
+ t.json :params
10
+ end
11
+
12
+ t.timestamps
13
+ end
14
+
15
+ create_table :noticed_notifications do |t|
16
+ t.string :type
17
+ t.belongs_to :event, null: false
18
+ t.belongs_to :recipient, polymorphic: true, null: false
19
+ t.datetime :read_at
20
+ t.datetime :seen_at
21
+
22
+ t.timestamps
23
+ end
24
+ end
25
+ end
@@ -12,7 +12,7 @@ module Noticed
12
12
  desc "Generates a class for a custom delivery method with the given NAME."
13
13
 
14
14
  def generate_notification
15
- template "delivery_method.rb", "app/notifications/delivery_methods/#{singular_name}.rb"
15
+ template "delivery_method.rb", "app/notifiers/delivery_methods/#{singular_name}.rb"
16
16
  end
17
17
  end
18
18
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Noticed
4
+ module Generators
5
+ class ModelGenerator < Rails::Generators::Base
6
+ include Rails::Generators::ResourceHelpers
7
+
8
+ source_root File.expand_path("../templates", __FILE__)
9
+
10
+ def create_migrations
11
+ rails_command "railties:install:migrations FROM=noticed", inline: true
12
+ end
13
+
14
+ def done
15
+ readme "README" if behavior == :invoke
16
+ end
17
+ end
18
+ end
19
+ end
@@ -4,7 +4,7 @@ require "rails/generators/named_base"
4
4
 
5
5
  module Noticed
6
6
  module Generators
7
- class NotificationGenerator < Rails::Generators::NamedBase
7
+ class NotifierGenerator < Rails::Generators::NamedBase
8
8
  include Rails::Generators::ResourceHelpers
9
9
 
10
10
  source_root File.expand_path("../templates", __FILE__)
@@ -12,7 +12,7 @@ module Noticed
12
12
  desc "Generates a notification with the given NAME."
13
13
 
14
14
  def generate_notification
15
- template "notification.rb", "app/notifications/#{file_path}.rb"
15
+ template "notifier.rb", "app/notifiers/#{file_path}.rb"
16
16
  end
17
17
  end
18
18
  end
@@ -1,7 +1,8 @@
1
1
 
2
- 🚚 Your notifications database model has been generated!
2
+ 🚚 You're ready to start sending notifications!
3
3
 
4
4
  Next steps:
5
- 1. Run "rails db:migrate"
6
- 2. Add "has_many :notifications, as: :recipient, dependent: :destroy" to your User model(s).
7
- 3. Generate notifications with "rails g noticed:notification"
5
+ 1. Run `rails db:migrate`
6
+ 2. Add `has_many :notifications, as: :recipient, dependent: :destroy, class_name: "Noticed::Notification"` to your User model(s).
7
+ 2. Add `has_many :notifications, as: :record, dependent: :destroy, class_name: "Noticed::Event"` to your model(s) that notifications reference.
8
+ 3. Generate notifiers with "rails g noticed:notifier"
@@ -1,12 +1,8 @@
1
- class DeliveryMethods::<%= class_name %> < Noticed::DeliveryMethods::Base
1
+ class DeliveryMethods::<%= class_name %> < Noticed::DeliveryMethod
2
+ # Specify the config options your delivery method requires in its config block
3
+ required_options # :foo, :bar
4
+
2
5
  def deliver
3
6
  # Logic for sending the notification
4
7
  end
5
-
6
- # You may override this method to validate options for the delivery method
7
- # Invalid options should raise a ValidationError
8
- #
9
- # def self.validate!(options)
10
- # raise ValidationError, "required_option missing" unless options[:required_option]
11
- # end
12
8
  end
@@ -0,0 +1,24 @@
1
+ # To deliver this notification:
2
+ #
3
+ # <%= class_name %>.with(record: @post, message: "New post").deliver(User.all)
4
+
5
+ class <%= class_name %> < Noticed::Event
6
+ # Add your delivery methods
7
+ #
8
+ # deliver_by :email do |config|
9
+ # config.mailer = "UserMailer"
10
+ # config.method = "new_post"
11
+ # end
12
+ #
13
+ # bulk_deliver_by :slack do |config|
14
+ # config.url = -> { Rails.application.credentials.slack_webhook_url }
15
+ # end
16
+ #
17
+ # deliver_by :custom do |config|
18
+ # config.class = "MyDeliveryMethod"
19
+ # end
20
+
21
+ # Add required params
22
+ #
23
+ # required_param :message
24
+ end
@@ -0,0 +1,44 @@
1
+ require "net/http"
2
+
3
+ module Noticed
4
+ module ApiClient
5
+ extend ActiveSupport::Concern
6
+
7
+ # Helper method for making POST requests from delivery methods
8
+ #
9
+ # Usage:
10
+ # post_request("http://example.com", basic_auth: {user:, pass:}, headers: {}, json: {}, form: {})
11
+ #
12
+ def post_request(url, args = {})
13
+ args.compact!
14
+
15
+ uri = URI(url)
16
+ http = Net::HTTP.new(uri.host, uri.port)
17
+ http.use_ssl = true if uri.instance_of? URI::HTTPS
18
+
19
+ headers = args.delete(:headers) || {}
20
+ headers["Content-Type"] = "application/json" if args.has_key?(:json)
21
+
22
+ request = Net::HTTP::Post.new(uri.request_uri, headers)
23
+
24
+ if (basic_auth = args.delete(:basic_auth))
25
+ request.basic_auth basic_auth.fetch(:user), basic_auth.fetch(:pass)
26
+ end
27
+
28
+ if (json = args.delete(:json))
29
+ request.body = json.to_json
30
+ elsif (form = args.delete(:form))
31
+ request.set_form(form, "multipart/form-data")
32
+ end
33
+
34
+ logger.debug("POST #{url}")
35
+ logger.debug(request.body)
36
+ response = http.request(request)
37
+ logger.debug("Response: #{response.code}: #{response.body.inspect}")
38
+
39
+ raise ResponseUnsuccessful.new(response, url, args) unless response.code.start_with?("20")
40
+
41
+ response
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,46 @@
1
+ module Noticed
2
+ class BulkDeliveryMethod < ApplicationJob
3
+ include ApiClient
4
+ include RequiredOptions
5
+
6
+ class_attribute :logger, default: Rails.logger
7
+
8
+ attr_reader :config, :event
9
+
10
+ def perform(delivery_method_name, event)
11
+ @event = event
12
+ @config = event.bulk_delivery_methods.fetch(delivery_method_name).config
13
+
14
+ return false if config.has_key?(:if) && !evaluate_option(:if)
15
+ return false if config.has_key?(:unless) && evaluate_option(:unless)
16
+
17
+ deliver
18
+ end
19
+
20
+ def deliver
21
+ raise NotImplementedError, "Bulk delivery methods must implement the `deliver` method"
22
+ end
23
+
24
+ def fetch_constant(name)
25
+ option = config[name]
26
+ option.is_a?(String) ? option.constantize : option
27
+ end
28
+
29
+ def evaluate_option(name)
30
+ option = config[name]
31
+
32
+ # Evaluate Proc within the context of the notifier
33
+ if option&.respond_to?(:call)
34
+ event.instance_exec(&option)
35
+
36
+ # Call method if symbol and matching method
37
+ elsif option.is_a?(Symbol) && event.respond_to?(option)
38
+ event.send(option)
39
+
40
+ # Return the value
41
+ else
42
+ option
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,11 @@
1
+ module Noticed
2
+ module BulkDeliveryMethods
3
+ class Discord < BulkDeliveryMethod
4
+ required_options :json, :url
5
+
6
+ def deliver
7
+ post_request evaluate_option(:url), headers: evaluate_option(:headers), json: evaluate_option(:json)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module Noticed
2
+ module BulkDeliveryMethods
3
+ class Slack < BulkDeliveryMethod
4
+ DEFAULT_URL = "https://slack.com/api/chat.postMessage"
5
+
6
+ required_options :json
7
+
8
+ def deliver
9
+ post_request url, headers: evaluate_option(:headers), json: evaluate_option(:json)
10
+ end
11
+
12
+ def url
13
+ evaluate_option(:url) || DEFAULT_URL
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ module Noticed
2
+ module BulkDeliveryMethods
3
+ class Webhook < BulkDeliveryMethod
4
+ required_options :url
5
+
6
+ def deliver
7
+ Rails.logger.debug(evaluate_option(:json))
8
+ post_request(
9
+ evaluate_option(:url),
10
+ basic_auth: evaluate_option(:basic_auth),
11
+ headers: evaluate_option(:headers),
12
+ json: evaluate_option(:json),
13
+ form: evaluate_option(:form)
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
data/lib/noticed/coder.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require "active_job/arguments"
2
+
1
3
  module Noticed
2
4
  class Coder
3
5
  def self.load(data)
@@ -0,0 +1,51 @@
1
+ module Noticed
2
+ class DeliveryMethod < ApplicationJob
3
+ include ApiClient
4
+ include RequiredOptions
5
+
6
+ class_attribute :logger, default: Rails.logger
7
+
8
+ attr_reader :config, :event, :notification
9
+ delegate :recipient, to: :notification
10
+ delegate :record, :params, to: :event
11
+
12
+ def perform(delivery_method_name, notification, overrides: {})
13
+ @notification = notification
14
+ @event = notification.event
15
+
16
+ # Look up config from Notifier and merge overrides
17
+ @config = event.delivery_methods.fetch(delivery_method_name).config.merge(overrides)
18
+
19
+ return false if config.has_key?(:if) && !evaluate_option(:if)
20
+ return false if config.has_key?(:unless) && evaluate_option(:unless)
21
+
22
+ deliver
23
+ end
24
+
25
+ def deliver
26
+ raise NotImplementedError, "Delivery methods must implement the `deliver` method"
27
+ end
28
+
29
+ def fetch_constant(name)
30
+ option = config[name]
31
+ option.is_a?(String) ? option.constantize : option
32
+ end
33
+
34
+ def evaluate_option(name)
35
+ option = config[name]
36
+
37
+ # Evaluate Proc within the context of the Notification
38
+ if option&.respond_to?(:call)
39
+ notification.instance_exec(&option)
40
+
41
+ # Call method if symbol and matching method on Notifier
42
+ elsif option.is_a?(Symbol) && event.respond_to?(option)
43
+ event.send(option, self)
44
+
45
+ # Return the value
46
+ else
47
+ option
48
+ end
49
+ end
50
+ end
51
+ end