caffeinate 0.2.1 → 0.7.0
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/README.md +142 -70
- data/app/controllers/caffeinate/campaign_subscriptions_controller.rb +3 -3
- data/app/models/caffeinate/application_record.rb +0 -1
- data/app/models/caffeinate/campaign.rb +25 -7
- data/app/models/caffeinate/campaign_subscription.rb +44 -14
- data/app/models/caffeinate/mailing.rb +14 -6
- data/app/views/layouts/{caffeinate.html.erb → _caffeinate.html.erb} +0 -0
- data/db/migrate/20201124183102_create_caffeinate_campaigns.rb +1 -0
- data/db/migrate/20201124183303_create_caffeinate_campaign_subscriptions.rb +5 -3
- data/db/migrate/20201124183419_create_caffeinate_mailings.rb +2 -1
- data/lib/caffeinate.rb +4 -18
- data/lib/caffeinate/action_mailer/extension.rb +1 -1
- data/lib/caffeinate/action_mailer/interceptor.rb +2 -2
- data/lib/caffeinate/action_mailer/observer.rb +4 -3
- data/lib/caffeinate/active_record/extension.rb +15 -10
- data/lib/caffeinate/configuration.rb +9 -2
- data/lib/caffeinate/drip.rb +22 -2
- data/lib/caffeinate/drip_evaluator.rb +1 -0
- data/lib/caffeinate/dripper/base.rb +4 -0
- data/lib/caffeinate/dripper/batching.rb +13 -11
- data/lib/caffeinate/dripper/callbacks.rb +46 -18
- data/lib/caffeinate/dripper/campaign.rb +18 -4
- data/lib/caffeinate/dripper/defaults.rb +1 -0
- data/lib/caffeinate/dripper/delivery.rb +7 -7
- data/lib/caffeinate/dripper/drip.rb +2 -41
- data/lib/caffeinate/dripper/drip_collection.rb +62 -0
- data/lib/caffeinate/dripper/inferences.rb +3 -1
- data/lib/caffeinate/dripper/perform.rb +12 -10
- data/lib/caffeinate/dripper/periodical.rb +26 -0
- data/lib/caffeinate/dripper/subscriber.rb +14 -2
- data/lib/caffeinate/dripper_collection.rb +17 -0
- data/lib/caffeinate/engine.rb +9 -2
- data/lib/caffeinate/mail_ext.rb +12 -0
- data/lib/caffeinate/version.rb +1 -1
- data/lib/generators/caffeinate/install_generator.rb +1 -1
- data/lib/generators/caffeinate/templates/caffeinate.rb +10 -0
- metadata +21 -3
@@ -17,12 +17,12 @@
|
|
17
17
|
module Caffeinate
|
18
18
|
# Records of the mails sent and to be sent for a given `::Caffeinate::CampaignSubscriber`
|
19
19
|
class Mailing < ApplicationRecord
|
20
|
-
CURRENT_THREAD_KEY = :current_caffeinate_mailing
|
21
|
-
|
22
20
|
self.table_name = 'caffeinate_mailings'
|
23
21
|
|
24
22
|
belongs_to :caffeinate_campaign_subscription, class_name: 'Caffeinate::CampaignSubscription'
|
23
|
+
alias_attribute :subscription, :caffeinate_campaign_subscription
|
25
24
|
has_one :caffeinate_campaign, through: :caffeinate_campaign_subscription
|
25
|
+
alias_attribute :campaign, :caffeinate_campaign
|
26
26
|
|
27
27
|
scope :upcoming, -> { unsent.unskipped.where('send_at < ?', ::Caffeinate.config.time_now).order('send_at asc') }
|
28
28
|
scope :unsent, -> { unskipped.where(sent_at: nil) }
|
@@ -30,6 +30,13 @@ module Caffeinate
|
|
30
30
|
scope :skipped, -> { where.not(skipped_at: nil) }
|
31
31
|
scope :unskipped, -> { where(skipped_at: nil) }
|
32
32
|
|
33
|
+
def initialize_dup(args)
|
34
|
+
super
|
35
|
+
self.send_at = nil
|
36
|
+
self.sent_at = nil
|
37
|
+
self.skipped_at = nil
|
38
|
+
end
|
39
|
+
|
33
40
|
# Checks if the Mailing is not skipped and not sent
|
34
41
|
def pending?
|
35
42
|
unskipped? && unsent?
|
@@ -59,13 +66,12 @@ module Caffeinate
|
|
59
66
|
def skip!
|
60
67
|
update!(skipped_at: Caffeinate.config.time_now)
|
61
68
|
|
62
|
-
caffeinate_campaign.to_dripper.run_callbacks(:on_skip,
|
69
|
+
caffeinate_campaign.to_dripper.run_callbacks(:on_skip, self)
|
63
70
|
end
|
64
71
|
|
65
72
|
# The associated drip
|
66
|
-
# @todo This can be optimized with a better cache
|
67
73
|
def drip
|
68
|
-
@drip ||= caffeinate_campaign.to_dripper.drip_collection
|
74
|
+
@drip ||= caffeinate_campaign.to_dripper.drip_collection.for(mailer_action)
|
69
75
|
end
|
70
76
|
|
71
77
|
# The associated Subscriber from `::Caffeinate::CampaignSubscription`
|
@@ -80,7 +86,7 @@ module Caffeinate
|
|
80
86
|
|
81
87
|
# Assigns attributes to the Mailing from the Drip
|
82
88
|
def from_drip(drip)
|
83
|
-
self.send_at = drip.send_at
|
89
|
+
self.send_at = drip.send_at(self)
|
84
90
|
self.mailer_class = drip.options[:mailer_class]
|
85
91
|
self.mailer_action = drip.action
|
86
92
|
self
|
@@ -93,6 +99,8 @@ module Caffeinate
|
|
93
99
|
else
|
94
100
|
deliver!
|
95
101
|
end
|
102
|
+
|
103
|
+
caffeinate_campaign_subscription.touch
|
96
104
|
end
|
97
105
|
|
98
106
|
# Delivers the Mailing in the foreground
|
File without changes
|
@@ -7,17 +7,19 @@ class CreateCaffeinateCampaignSubscriptions < ActiveRecord::Migration[6.0]
|
|
7
7
|
create_table :caffeinate_campaign_subscriptions do |t|
|
8
8
|
t.references :caffeinate_campaign, null: false, index: { name: :caffeineate_campaign_subscriptions_on_campaign }, foreign_key: true
|
9
9
|
t.string :subscriber_type, null: false
|
10
|
-
t.
|
10
|
+
t.integer :subscriber_id, null: false
|
11
11
|
t.string :user_type
|
12
|
-
t.
|
12
|
+
t.integer :user_id
|
13
13
|
t.string :token, null: false
|
14
14
|
t.datetime :ended_at
|
15
|
+
t.string :ended_reason
|
15
16
|
t.datetime :resubscribed_at
|
16
17
|
t.datetime :unsubscribed_at
|
18
|
+
t.string :unsubscribe_reason
|
17
19
|
|
18
20
|
t.timestamps
|
19
21
|
end
|
20
22
|
add_index :caffeinate_campaign_subscriptions, :token, unique: true
|
21
|
-
add_index :caffeinate_campaign_subscriptions, %i[subscriber_id subscriber_type user_id user_type], name: :index_caffeinate_campaign_subscriptions
|
23
|
+
add_index :caffeinate_campaign_subscriptions, %i[caffeinate_campaign_id subscriber_id subscriber_type user_id user_type ended_at resubscribed_at unsubscribed_at], name: :index_caffeinate_campaign_subscriptions
|
22
24
|
end
|
23
25
|
end
|
@@ -14,6 +14,7 @@ class CreateCaffeinateMailings < ActiveRecord::Migration[6.0]
|
|
14
14
|
|
15
15
|
t.timestamps
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
|
+
add_index :caffeinate_mailings, %i[caffeinate_campaign_subscription_id send_at sent_at skipped_at], name: :index_caffeinate_mailings
|
18
19
|
end
|
19
20
|
end
|
data/lib/caffeinate.rb
CHANGED
@@ -1,22 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rails/all'
|
4
|
+
require 'caffeinate/mail_ext'
|
4
5
|
require 'caffeinate/engine'
|
5
6
|
require 'caffeinate/drip'
|
6
7
|
require 'caffeinate/url_helpers'
|
7
8
|
require 'caffeinate/configuration'
|
8
9
|
require 'caffeinate/dripper/base'
|
9
10
|
require 'caffeinate/deliver_async'
|
11
|
+
require 'caffeinate/dripper_collection'
|
10
12
|
|
11
13
|
module Caffeinate
|
12
|
-
|
13
|
-
|
14
|
-
@dripper_to_campaign_class ||= {}
|
15
|
-
end
|
16
|
-
|
17
|
-
# Convenience method for `dripper_to_campaign_class`
|
18
|
-
def self.register_dripper(name, klass)
|
19
|
-
dripper_to_campaign_class[name.to_sym] = klass
|
14
|
+
def self.dripper_collection
|
15
|
+
@drippers ||= DripperCollection.new
|
20
16
|
end
|
21
17
|
|
22
18
|
# Global configuration
|
@@ -28,14 +24,4 @@ module Caffeinate
|
|
28
24
|
def self.setup
|
29
25
|
yield config
|
30
26
|
end
|
31
|
-
|
32
|
-
# The current mailing
|
33
|
-
def self.current_mailing=(val)
|
34
|
-
Thread.current[::Caffeinate::Mailing::CURRENT_THREAD_KEY] = val
|
35
|
-
end
|
36
|
-
|
37
|
-
# The current mailing
|
38
|
-
def self.current_mailing
|
39
|
-
Thread.current[::Caffeinate::Mailing::CURRENT_THREAD_KEY]
|
40
|
-
end
|
41
27
|
end
|
@@ -7,7 +7,7 @@ module Caffeinate
|
|
7
7
|
module Extension
|
8
8
|
def self.included(klass)
|
9
9
|
klass.before_action do
|
10
|
-
@mailing =
|
10
|
+
@mailing = params[:mailing] if params
|
11
11
|
end
|
12
12
|
|
13
13
|
klass.helper_method :caffeinate_unsubscribe_url, :caffeinate_subscribe_url
|
@@ -7,10 +7,10 @@ module Caffeinate
|
|
7
7
|
class Interceptor
|
8
8
|
# Handles `before_send` callbacks for a `Caffeinate::Dripper`
|
9
9
|
def self.delivering_email(message)
|
10
|
-
mailing =
|
10
|
+
mailing = message.caffeinate_mailing
|
11
11
|
return unless mailing
|
12
12
|
|
13
|
-
mailing.caffeinate_campaign.to_dripper.run_callbacks(:before_send, mailing
|
13
|
+
mailing.caffeinate_campaign.to_dripper.run_callbacks(:before_send, mailing, message)
|
14
14
|
drip = mailing.drip
|
15
15
|
message.perform_deliveries = drip.enabled?(mailing)
|
16
16
|
end
|
@@ -2,15 +2,16 @@
|
|
2
2
|
|
3
3
|
module Caffeinate
|
4
4
|
module ActionMailer
|
5
|
-
# Handles updating the Caffeinate::Message if it's available in
|
5
|
+
# Handles updating the Caffeinate::Message if it's available in Mail::Message.caffeinate_mailing
|
6
6
|
# and runs any associated callbacks
|
7
7
|
class Observer
|
8
8
|
def self.delivered_email(message)
|
9
|
-
mailing =
|
9
|
+
mailing = message.caffeinate_mailing
|
10
10
|
return unless mailing
|
11
11
|
|
12
12
|
mailing.update!(sent_at: Caffeinate.config.time_now, skipped_at: nil) if message.perform_deliveries
|
13
|
-
mailing.caffeinate_campaign.to_dripper.run_callbacks(:after_send, mailing
|
13
|
+
mailing.caffeinate_campaign.to_dripper.run_callbacks(:after_send, mailing, message)
|
14
|
+
true
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
@@ -5,30 +5,35 @@ module Caffeinate
|
|
5
5
|
# Includes the ActiveRecord association and relevant scopes for an ActiveRecord-backed model
|
6
6
|
module Extension
|
7
7
|
# Adds the associations for a subscriber
|
8
|
-
def
|
8
|
+
def acts_as_caffeinate_subscriber
|
9
9
|
has_many :caffeinate_campaign_subscriptions, as: :subscriber, class_name: '::Caffeinate::CampaignSubscription', dependent: :destroy
|
10
10
|
has_many :caffeinate_campaigns, through: :caffeinate_campaign_subscriptions, class_name: '::Caffeinate::Campaign'
|
11
11
|
has_many :caffeinate_mailings, through: :caffeinate_campaign_subscriptions, class_name: '::Caffeinate::Mailing'
|
12
12
|
|
13
13
|
scope :not_subscribed_to_campaign, lambda { |list|
|
14
|
-
|
15
|
-
|
14
|
+
where.not(id: ::Caffeinate::CampaignSubscription
|
15
|
+
.select(:subscriber_id)
|
16
|
+
.joins(:caffeinate_campaign)
|
17
|
+
.where(subscriber_type: name, caffeinate_campaigns: { slug: list }))
|
16
18
|
}
|
17
19
|
|
18
20
|
scope :unsubscribed_from_campaign, lambda { |list|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
where(id: unsubscribed)
|
21
|
+
where(id: ::Caffeinate::CampaignSubscription
|
22
|
+
.unsubscribed
|
23
|
+
.select(:subscriber_id)
|
24
|
+
.joins(:caffeinate_campaign)
|
25
|
+
.where(subscriber_type: name, caffeinate_campaigns: { slug: list }))
|
25
26
|
}
|
26
27
|
end
|
28
|
+
alias caffeinate_subscriber acts_as_caffeinate_subscriber
|
27
29
|
|
28
30
|
# Adds the associations for a user
|
29
|
-
def
|
31
|
+
def acts_as_caffeinate_user
|
30
32
|
has_many :caffeinate_campaign_subscriptions_as_user, as: :user, class_name: '::Caffeinate::CampaignSubscription'
|
33
|
+
has_many :caffeinate_campaigns_as_user, through: :caffeinate_campaign_subscriptions_as_user, class_name: '::Caffeinate::Campaign'
|
34
|
+
has_many :caffeinate_mailings_as_user, through: :caffeinate_campaign_subscriptions_as_user, class_name: '::Caffeinate::Campaign'
|
31
35
|
end
|
36
|
+
alias caffeinate_user acts_as_caffeinate_user
|
32
37
|
end
|
33
38
|
end
|
34
39
|
end
|
@@ -3,19 +3,26 @@
|
|
3
3
|
module Caffeinate
|
4
4
|
# Global configuration
|
5
5
|
class Configuration
|
6
|
-
attr_accessor :now, :async_delivery, :mailing_job, :batch_size
|
6
|
+
attr_accessor :now, :async_delivery, :mailing_job, :batch_size, :drippers_path, :implicit_campaigns
|
7
7
|
|
8
8
|
def initialize
|
9
9
|
@now = -> { Time.current }
|
10
10
|
@async_delivery = false
|
11
11
|
@mailing_job = nil
|
12
12
|
@batch_size = 1_000
|
13
|
+
@drippers_path = 'app/drippers'
|
14
|
+
@implicit_campaigns = true
|
13
15
|
end
|
14
16
|
|
15
17
|
def now=(val)
|
16
18
|
raise ArgumentError, '#now must be a proc' unless val.respond_to?(:call)
|
17
19
|
|
18
|
-
|
20
|
+
@now = val
|
21
|
+
end
|
22
|
+
|
23
|
+
# Automatically create a `::Caffeinate::Campaign` object if not found per `Dripper.inferred_campaign_slug`
|
24
|
+
def implicit_campaigns?
|
25
|
+
@implicit_campaigns == true
|
19
26
|
end
|
20
27
|
|
21
28
|
# The current time, for database calls
|
data/lib/caffeinate/drip.rb
CHANGED
@@ -7,6 +7,7 @@ module Caffeinate
|
|
7
7
|
# Handles the block and provides convenience methods for the drip
|
8
8
|
class Drip
|
9
9
|
attr_reader :dripper, :action, :options, :block
|
10
|
+
|
10
11
|
def initialize(dripper, action, options, &block)
|
11
12
|
@dripper = dripper
|
12
13
|
@action = action
|
@@ -19,12 +20,31 @@ module Caffeinate
|
|
19
20
|
options[:using] == :parameterized
|
20
21
|
end
|
21
22
|
|
22
|
-
def send_at
|
23
|
-
|
23
|
+
def send_at(mailing = nil)
|
24
|
+
if periodical?
|
25
|
+
start = mailing.instance_exec(&options[:start])
|
26
|
+
start += options[:every] if mailing.caffeinate_campaign_subscription.caffeinate_mailings.count.positive?
|
27
|
+
date = start.from_now
|
28
|
+
else
|
29
|
+
date = options[:delay].from_now
|
30
|
+
end
|
31
|
+
|
32
|
+
if options[:at]
|
33
|
+
time = Time.parse(options[:at])
|
34
|
+
return date.change(hour: time.hour, min: time.min, sec: time.sec)
|
35
|
+
end
|
36
|
+
|
37
|
+
date
|
38
|
+
end
|
39
|
+
|
40
|
+
def periodical?
|
41
|
+
options[:every].present?
|
24
42
|
end
|
25
43
|
|
26
44
|
# Checks if the drip is enabled
|
27
45
|
def enabled?(mailing)
|
46
|
+
dripper.run_callbacks(:before_drip, self, mailing)
|
47
|
+
|
28
48
|
DripEvaluator.new(mailing).call(&@block)
|
29
49
|
end
|
30
50
|
end
|
@@ -8,6 +8,7 @@ require 'caffeinate/dripper/delivery'
|
|
8
8
|
require 'caffeinate/dripper/drip'
|
9
9
|
require 'caffeinate/dripper/inferences'
|
10
10
|
require 'caffeinate/dripper/perform'
|
11
|
+
require 'caffeinate/dripper/periodical'
|
11
12
|
require 'caffeinate/dripper/subscriber'
|
12
13
|
|
13
14
|
module Caffeinate
|
@@ -22,7 +23,10 @@ module Caffeinate
|
|
22
23
|
include Drip
|
23
24
|
include Inferences
|
24
25
|
include Perform
|
26
|
+
include Periodical
|
25
27
|
include Subscriber
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
31
|
+
|
32
|
+
ActiveSupport.run_load_hooks :caffeinate, Caffeinate::Dripper::Base
|
@@ -1,19 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Caffeinate
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
klass
|
8
|
-
|
9
|
-
|
10
|
-
module ClassMethods
|
11
|
-
def batch_size(num)
|
12
|
-
@_batch_size = num
|
4
|
+
module Dripper
|
5
|
+
# Includes batch support for setting the batch size for Perform
|
6
|
+
module Batching
|
7
|
+
def self.included(klass)
|
8
|
+
klass.extend ClassMethods
|
13
9
|
end
|
14
10
|
|
15
|
-
|
16
|
-
|
11
|
+
module ClassMethods
|
12
|
+
def batch_size=(num)
|
13
|
+
@batch_size = num
|
14
|
+
end
|
15
|
+
|
16
|
+
def batch_size
|
17
|
+
@batch_size || ::Caffeinate.config.batch_size
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
@@ -38,20 +38,36 @@ module Caffeinate
|
|
38
38
|
@on_subscribe_blocks ||= []
|
39
39
|
end
|
40
40
|
|
41
|
+
# Callback after a Caffeinate::CampaignSubscription is `#resubscribed!`
|
42
|
+
#
|
43
|
+
# on_resubscribe do |campaign_subscription|
|
44
|
+
# Slack.notify(:caffeinate, "Someone resubscribed to #{campaign_subscription.campaign.name}!")
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# @yield Caffeinate::CampaignSubscription
|
48
|
+
def on_resubscribe(&block)
|
49
|
+
on_resubscribe_blocks << block
|
50
|
+
end
|
51
|
+
|
52
|
+
# :nodoc:
|
53
|
+
def on_resubscribe_blocks
|
54
|
+
@on_resubscribe_blocks ||= []
|
55
|
+
end
|
56
|
+
|
41
57
|
# Callback before the mailings get processed.
|
42
58
|
#
|
43
|
-
#
|
59
|
+
# before_perform do |dripper|
|
44
60
|
# Slack.notify(:caffeinate, "Dripper is getting ready for mailing! #{dripper.caffeinate_campaign.name}!")
|
45
61
|
# end
|
46
62
|
#
|
47
63
|
# @yield Caffeinate::Dripper
|
48
|
-
def
|
49
|
-
|
64
|
+
def before_perform(&block)
|
65
|
+
before_perform_blocks << block
|
50
66
|
end
|
51
67
|
|
52
68
|
# :nodoc:
|
53
|
-
def
|
54
|
-
@
|
69
|
+
def before_perform_blocks
|
70
|
+
@before_perform_blocks ||= []
|
55
71
|
end
|
56
72
|
|
57
73
|
# Callback before the mailings get processed in a batch.
|
@@ -62,13 +78,13 @@ module Caffeinate
|
|
62
78
|
#
|
63
79
|
# @yield Caffeinate::Dripper
|
64
80
|
# @yield Caffeinate::Mailing [Array]
|
65
|
-
def
|
66
|
-
|
81
|
+
def on_perform(&block)
|
82
|
+
on_perform_blocks << block
|
67
83
|
end
|
68
84
|
|
69
85
|
# :nodoc:
|
70
|
-
def
|
71
|
-
@
|
86
|
+
def on_perform_blocks
|
87
|
+
@on_perform_blocks ||= []
|
72
88
|
end
|
73
89
|
|
74
90
|
# Callback after the all the mailings have been sent.
|
@@ -79,13 +95,13 @@ module Caffeinate
|
|
79
95
|
#
|
80
96
|
# @yield Caffeinate::Dripper
|
81
97
|
# @yield Caffeinate::Mailing [Array]
|
82
|
-
def
|
83
|
-
|
98
|
+
def after_perform(&block)
|
99
|
+
after_perform_blocks << block
|
84
100
|
end
|
85
101
|
|
86
102
|
# :nodoc:
|
87
|
-
def
|
88
|
-
@
|
103
|
+
def after_perform_blocks
|
104
|
+
@after_perform_blocks ||= []
|
89
105
|
end
|
90
106
|
|
91
107
|
# Callback before a Drip has called the mailer.
|
@@ -94,9 +110,8 @@ module Caffeinate
|
|
94
110
|
# Slack.notify(:caffeinate, "#{drip.action_name} is starting")
|
95
111
|
# end
|
96
112
|
#
|
97
|
-
# @yield Caffeinate::CampaignSubscription
|
98
|
-
# @yield Caffeinate::Mailing
|
99
113
|
# @yield Caffeinate::Drip current drip
|
114
|
+
# @yield Caffeinate::Mailing
|
100
115
|
def before_drip(&block)
|
101
116
|
before_drip_blocks << block
|
102
117
|
end
|
@@ -112,7 +127,6 @@ module Caffeinate
|
|
112
127
|
# Slack.notify(:caffeinate, "A new subscriber to #{campaign_subscription.campaign.name}!")
|
113
128
|
# end
|
114
129
|
#
|
115
|
-
# @yield Caffeinate::CampaignSubscription
|
116
130
|
# @yield Caffeinate::Mailing
|
117
131
|
# @yield Mail::Message
|
118
132
|
def before_send(&block)
|
@@ -130,7 +144,6 @@ module Caffeinate
|
|
130
144
|
# Slack.notify(:caffeinate, "A new subscriber to #{campaign_subscription.campaign.name}!")
|
131
145
|
# end
|
132
146
|
#
|
133
|
-
# @yield Caffeinate::CampaignSubscription
|
134
147
|
# @yield Caffeinate::Mailing
|
135
148
|
# @yield Mail::Message
|
136
149
|
def after_send(&block)
|
@@ -174,13 +187,28 @@ module Caffeinate
|
|
174
187
|
@on_unsubscribe_blocks ||= []
|
175
188
|
end
|
176
189
|
|
190
|
+
# Callback after a CampaignSubscriber has ended.
|
191
|
+
#
|
192
|
+
# on_end do |campaign_sub|
|
193
|
+
# Slack.notify(:caffeinate, "#{campaign_sub.id} has ended... sad day.")
|
194
|
+
# end
|
195
|
+
#
|
196
|
+
# @yield Caffeinate::CampaignSubscription
|
197
|
+
def on_end(&block)
|
198
|
+
on_end_blocks << block
|
199
|
+
end
|
200
|
+
|
201
|
+
# :nodoc:
|
202
|
+
def on_end_blocks
|
203
|
+
@on_end_blocks ||= []
|
204
|
+
end
|
205
|
+
|
177
206
|
# Callback after a `Caffeinate::Mailing` is skipped.
|
178
207
|
#
|
179
208
|
# on_skip do |campaign_subscription, mailing, message|
|
180
209
|
# Slack.notify(:caffeinate, "#{campaign_sub.id} has unsubscribed... sad day.")
|
181
210
|
# end
|
182
211
|
#
|
183
|
-
# @yield `Caffeinate::CampaignSubscription`
|
184
212
|
# @yield `Caffeinate::Mailing`
|
185
213
|
def on_skip(&block)
|
186
214
|
on_skip_blocks << block
|