caffeinate 0.8.5 → 0.12.0

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: 5f2ea2b9f5f03fdeb85614ae404df166822797d18861bd1c6ea5c4c867f44618
4
- data.tar.gz: 38b8cd78227cc1eecffe4e09ee01fd8e26a7fc46314d30956ce29230b1209f7f
3
+ metadata.gz: 80e462cd99749a8f1352d481fec74d6a053a1660d200888a93844205eafb984c
4
+ data.tar.gz: 1c709353c202c7a97eb2fd8067f31ee40ee2753d93f8771232494867d47ce9c0
5
5
  SHA512:
6
- metadata.gz: 3fd342f50ad5394c5253d1c7c00efa7ce25e1d1f90571fe16658bed9f0d251893f4953d746daf4db48728541d13fc67ee505529aae18711e491ca0819f66d6a1
7
- data.tar.gz: 8ec91a5b080a1420f090a4c538c1fd1cd05def80c5aa5395ce2a2d985063e4ef7d26e935ec1131496525d44bd745abbac90cbbc749e9ec6b55d1c0f3a99d8e49
6
+ metadata.gz: 9d4261e176299efc975f8d11791c95a58740bd94eaa6ae2e931fb262240f9e24a27cc1c88230965386ff4658e037dcbeb00ebf2100399d077872be0196e3ba8c
7
+ data.tar.gz: 208bc056825501459d0247e4fa91f64b3d9c4408f8219d7f47aa6dd492e9b183e614adeb97b5746f3e9c686d31aa38035667cc003142c93417f1d6cb8935b906
@@ -54,6 +54,14 @@ module Caffeinate
54
54
  #
55
55
  # Just... mintier.
56
56
  def unsubscribe(subscriber, **args)
57
+ reason = args.delete(:reason)
58
+ subscription = subscriber(subscriber, **args)
59
+ return false if subscription.nil?
60
+
61
+ subscription.unsubscribe(reason)
62
+ end
63
+
64
+ def unsubscribe!(subscriber, **args)
57
65
  reason = args.delete(:reason)
58
66
  subscription = subscriber(subscriber, **args)
59
67
  raise ::ActiveRecord::RecordInvalid, subscription if subscription.nil?
@@ -64,12 +72,12 @@ module Caffeinate
64
72
  # Creates a `CampaignSubscription` object for the present Campaign. Allows passing `**args` to
65
73
  # delegate additional arguments to the record. Uses `find_or_create_by`.
66
74
  def subscribe(subscriber, **args)
67
- caffeinate_campaign_subscriptions.find_or_create_by(subscriber: subscriber, **args)
75
+ caffeinate_campaign_subscriptions.create(subscriber: subscriber, **args)
68
76
  end
69
77
 
70
78
  # Subscribes an object to a campaign. Raises `ActiveRecord::RecordInvalid` if the record was invalid.
71
79
  def subscribe!(subscriber, **args)
72
- subscribe(subscriber, **args)
80
+ caffeinate_campaign_subscriptions.create!(subscriber: subscriber, **args)
73
81
  end
74
82
  end
75
83
  end
@@ -28,9 +28,10 @@ module Caffeinate
28
28
 
29
29
  has_many :caffeinate_mailings, class_name: 'Caffeinate::Mailing', foreign_key: :caffeinate_campaign_subscription_id, dependent: :destroy
30
30
  has_many :mailings, class_name: 'Caffeinate::Mailing', foreign_key: :caffeinate_campaign_subscription_id, dependent: :destroy
31
+ has_many :future_mailings, -> { upcoming.unsent }, class_name: '::Caffeinate::Mailing', foreign_key: :caffeinate_campaign_subscription_id
31
32
 
32
- has_one :next_caffeinate_mailing, -> { upcoming.unsent.order(send_at: :asc) }, class_name: '::Caffeinate::Mailing', foreign_key: :caffeinate_campaign_subscription_id
33
- has_one :next_mailing, -> { upcoming.unsent.order(send_at: :asc) }, class_name: '::Caffeinate::Mailing', foreign_key: :caffeinate_campaign_subscription_id
33
+ has_one :next_caffeinate_mailing, -> { joins(:caffeinate_campaign_subscription).where(caffeinate_campaign_subscriptions: { ended_at: nil, unsubscribed_at: nil }).upcoming.unsent.order(send_at: :asc) }, class_name: '::Caffeinate::Mailing', foreign_key: :caffeinate_campaign_subscription_id
34
+ has_one :next_mailing, -> { joins(:caffeinate_campaign_subscription).where(caffeinate_campaign_subscriptions: { ended_at: nil, unsubscribed_at: nil }).upcoming.unsent.order(send_at: :asc) }, class_name: '::Caffeinate::Mailing', foreign_key: :caffeinate_campaign_subscription_id
34
35
 
35
36
  belongs_to :caffeinate_campaign, class_name: 'Caffeinate::Campaign', foreign_key: :caffeinate_campaign_id
36
37
  alias_attribute :campaign, :caffeinate_campaign
@@ -49,6 +50,8 @@ module Caffeinate
49
50
  before_validation :set_token!, on: [:create]
50
51
  validates :token, uniqueness: true, on: [:create]
51
52
 
53
+ before_validation :call_dripper_before_subscribe_blocks!, on: :create
54
+
52
55
  after_commit :create_mailings!, on: :create
53
56
 
54
57
  after_commit :on_complete, if: :completed?
@@ -83,6 +86,16 @@ module Caffeinate
83
86
  true
84
87
  end
85
88
 
89
+ # Updates `ended_at` and runs `on_complete` callbacks
90
+ def end(reason = nil)
91
+ return false if unsubscribed?
92
+
93
+ result = update(ended_at: ::Caffeinate.config.time_now, ended_reason: reason)
94
+
95
+ caffeinate_campaign.to_dripper.run_callbacks(:on_end, self)
96
+ result
97
+ end
98
+
86
99
  # Updates `unsubscribed_at` and runs `on_subscribe` callbacks
87
100
  def unsubscribe!(reason = nil)
88
101
  raise ::Caffeinate::InvalidState, 'CampaignSubscription is already ended.' if ended?
@@ -93,6 +106,16 @@ module Caffeinate
93
106
  true
94
107
  end
95
108
 
109
+ # Updates `unsubscribed_at` and runs `on_subscribe` callbacks
110
+ def unsubscribe(reason = nil)
111
+ return false if ended?
112
+
113
+ result = update(unsubscribed_at: ::Caffeinate.config.time_now, unsubscribe_reason: reason)
114
+
115
+ caffeinate_campaign.to_dripper.run_callbacks(:on_unsubscribe, self)
116
+ result
117
+ end
118
+
96
119
  # Updates `unsubscribed_at` to nil and runs `on_subscribe` callbacks.
97
120
  # Use `force` to forcefully reset. Does not create the mailings.
98
121
  def resubscribe!(force = false)
@@ -105,12 +128,28 @@ module Caffeinate
105
128
  true
106
129
  end
107
130
 
131
+ # Updates `unsubscribed_at` to nil and runs `on_subscribe` callbacks.
132
+ # Use `force` to forcefully reset. Does not create the mailings.
133
+ def resubscribe!(force = false)
134
+ return false if ended? && !force
135
+ return false if unsubscribed? && !force
136
+
137
+ result = update(unsubscribed_at: nil, resubscribed_at: ::Caffeinate.config.time_now)
138
+
139
+ caffeinate_campaign.to_dripper.run_callbacks(:on_resubscribe, self)
140
+ result
141
+ end
142
+
108
143
  def completed?
109
144
  caffeinate_mailings.unsent.count.zero?
110
145
  end
111
146
 
112
147
  private
113
148
 
149
+ def call_dripper_before_subscribe_blocks!
150
+ caffeinate_campaign.to_dripper.run_callbacks(:before_subscribe, self)
151
+ end
152
+
114
153
  def on_complete
115
154
  caffeinate_campaign.to_dripper.run_callbacks(:on_complete, self)
116
155
  end
@@ -30,6 +30,8 @@ module Caffeinate
30
30
  scope :skipped, -> { where.not(skipped_at: nil) }
31
31
  scope :unskipped, -> { where(skipped_at: nil) }
32
32
 
33
+ after_touch :end_if_no_mailings!
34
+
33
35
  def initialize_dup(args)
34
36
  super
35
37
  self.send_at = nil
@@ -119,5 +121,9 @@ module Caffeinate
119
121
  raise NoMethodError, "Neither perform_later or perform_async are defined on #{klass}."
120
122
  end
121
123
  end
124
+
125
+ def end_if_no_mailings!
126
+ end! if future_mailings.empty?
127
+ end
122
128
  end
123
129
  end
@@ -6,6 +6,26 @@ module Caffeinate
6
6
  #
7
7
  # Handles the block and provides convenience methods for the drip
8
8
  class Drip
9
+ class OptionEvaluator
10
+ def initialize(thing, drip, mailing)
11
+ @thing = thing
12
+ @drip = drip
13
+ @mailing = mailing
14
+ end
15
+
16
+ def call
17
+ if @thing.is_a?(Symbol)
18
+ @drip.dripper.new.send(@thing, @drip, @mailing)
19
+ elsif @thing.is_a?(Proc)
20
+ @mailing.instance_exec(&@thing)
21
+ elsif @thing.is_a?(String)
22
+ Time.parse(@thing)
23
+ else
24
+ @thing
25
+ end
26
+ end
27
+ end
28
+
9
29
  attr_reader :dripper, :action, :options, :block
10
30
 
11
31
  def initialize(dripper, action, options, &block)
@@ -26,13 +46,16 @@ module Caffeinate
26
46
  start += options[:every] if mailing.caffeinate_campaign_subscription.caffeinate_mailings.count.positive?
27
47
  date = start.from_now
28
48
  elsif options[:on]
29
- date = mailing.instance_exec(&options[:on])
49
+ date = OptionEvaluator.new(options[:on], self, mailing).call
30
50
  else
31
- date = options[:delay].from_now
51
+ date = OptionEvaluator.new(options[:delay], self, mailing).call
52
+ if date.respond_to?(:from_now)
53
+ date = date.from_now
54
+ end
32
55
  end
33
56
 
34
57
  if options[:at]
35
- time = Time.parse(options[:at])
58
+ time = OptionEvaluator.new(options[:at], self, mailing).call
36
59
  return date.change(hour: time.hour, min: time.min, sec: time.sec)
37
60
  end
38
61
 
@@ -11,26 +11,29 @@ module Caffeinate
11
11
 
12
12
  def call(&block)
13
13
  return true unless block
14
-
15
- instance_eval(&block)
14
+ catch(:abort) do
15
+ result = instance_eval(&block)
16
+ return result.nil? || result === true
17
+ end
18
+ false
16
19
  end
17
20
 
18
21
  # Ends the CampaignSubscription
19
- def end!(msg)
20
- mailing.caffeinate_campaign_subscription.end!(msg)
21
- false
22
+ def end!(*args)
23
+ mailing.caffeinate_campaign_subscription.end!(*args)
24
+ throw(:abort)
22
25
  end
23
26
 
24
27
  # Unsubscribes the CampaignSubscription
25
- def unsubscribe!(msg)
26
- mailing.caffeinate_campaign_subscription.unsubscribe!(msg)
27
- false
28
+ def unsubscribe!(*args)
29
+ mailing.caffeinate_campaign_subscription.unsubscribe!(*args)
30
+ throw(:abort)
28
31
  end
29
32
 
30
33
  # Skips the mailing
31
34
  def skip!
32
35
  mailing.skip!
33
- false
36
+ throw(:abort)
34
37
  end
35
38
  end
36
39
  end
@@ -21,6 +21,14 @@ module Caffeinate
21
21
  end
22
22
  end
23
23
 
24
+ def before_subscribe(&block)
25
+ before_subscribe_blocks << block
26
+ end
27
+
28
+ def before_subscribe_blocks
29
+ @before_subscribe_blocks ||= []
30
+ end
31
+
24
32
  # Callback after a Caffeinate::CampaignSubscription is created, and after the Caffeinate::Mailings have
25
33
  # been created.
26
34
  #
@@ -16,11 +16,7 @@ module Caffeinate
16
16
  # @return nil
17
17
  def perform!
18
18
  run_callbacks(:before_perform, self)
19
- Caffeinate::Mailing
20
- .upcoming
21
- .unsent
22
- .joins(:caffeinate_campaign_subscription)
23
- .merge(Caffeinate::CampaignSubscription.active.where(caffeinate_campaign: self.campaign))
19
+ self.class.upcoming_mailings
24
20
  .in_batches(of: self.class.batch_size)
25
21
  .each do |batch|
26
22
  run_callbacks(:on_perform, self, batch)
@@ -35,6 +31,14 @@ module Caffeinate
35
31
  def perform!
36
32
  new.perform!
37
33
  end
34
+
35
+ def upcoming_mailings
36
+ Caffeinate::Mailing
37
+ .upcoming
38
+ .unsent
39
+ .joins(:caffeinate_campaign_subscription)
40
+ .merge(Caffeinate::CampaignSubscription.active.where(caffeinate_campaign: campaign))
41
+ end
38
42
  end
39
43
  end
40
44
  end
@@ -31,10 +31,10 @@ module Caffeinate
31
31
  #
32
32
  # @return [Caffeinate::CampaignSubscriber] the created CampaignSubscriber
33
33
  def subscribe(subscriber, **args)
34
- caffeinate_campaign.subscribe(subscriber, **args)
34
+ caffeinate_campaign.subscribe!(subscriber, **args)
35
35
  end
36
36
 
37
- # Unsubscribes from the campaign.
37
+ # Unsubscribes from the campaign. Returns false if something's wrong.
38
38
  #
39
39
  # OrderDripper.unsubscribe(order, user: order.user)
40
40
  #
@@ -46,6 +46,18 @@ module Caffeinate
46
46
  caffeinate_campaign.unsubscribe(subscriber, **args)
47
47
  end
48
48
 
49
+ # Unsubscribes from the campaign. Raises error if somerthing's wrong.
50
+ #
51
+ # OrderDripper.unsubscribe(order, user: order.user)
52
+ #
53
+ # @param [ActiveRecord::Base] subscriber The object subscribing
54
+ # @option [ActiveRecord::Base] :user The associated user (optional)
55
+ #
56
+ # @return [Caffeinate::CampaignSubscriber] the CampaignSubscriber
57
+ def unsubscribe!(subscriber, **args)
58
+ caffeinate_campaign.unsubscribe!(subscriber, **args)
59
+ end
60
+
49
61
  # :nodoc:
50
62
  def subscribes_block
51
63
  raise(NotImplementedError, 'Define subscribes') unless @subscribes_block
@@ -9,6 +9,13 @@ module Mail
9
9
  class Message
10
10
  attr_accessor :caffeinate_mailing
11
11
 
12
+ def caffeinate_mailing=(mailing)
13
+ @caffeinate_mailing = mailing
14
+ if mailing.is_a?(::Caffeinate::Mailing)
15
+ header['List-Unsubscribe'] = "<#{Caffeinate::UrlHelpers.caffeinate_subscribe_url(mailing.subscription)}>"
16
+ end
17
+ end
18
+
12
19
  def caffeinate?
13
20
  caffeinate_mailing.present?
14
21
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Caffeinate
4
- VERSION = '0.8.5'
4
+ VERSION = '0.12.0'
5
5
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Caffeinate
4
+ module Generators
5
+ # Creates a mailer from a dripper.
6
+ class MailerGenerator < Rails::Generators::Base
7
+ source_root File.expand_path('templates', __dir__)
8
+ include ::Rails::Generators::Migration
9
+ argument :dripper, banner: "dripper"
10
+
11
+ desc 'Creates a Mailer class from a dripper.'
12
+
13
+ def create_mailer
14
+ @dripper_klass = @dripper.safe_constantize
15
+ if @dripper_klass.nil?
16
+ raise ArgumentError, "Unknown dripper #{@dripper}"
17
+ end
18
+ @mailer_class = @dripper_klass.defaults[:mailer_class] || @dripper_klass.defaults[:mailer]
19
+ template 'mailer.rb', "app/mailers/#{@mailer_class.underscore}.rb"
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ class <%= @mailer_class %> < ApplicationMailer
2
+ <% @dripper_klass.drips.each do |action| -%>
3
+ def <%= action.action %><% if action.options[:using].nil? %>(mailing)<% end %>
4
+ <% if action.options[:using].nil? -%>
5
+ @mailing = mailing
6
+ <% end -%>
7
+ end
8
+ <% end -%>
9
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caffeinate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.5
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Brody
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-23 00:00:00.000000000 Z
11
+ date: 2021-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -175,8 +175,10 @@ files:
175
175
  - lib/caffeinate/url_helpers.rb
176
176
  - lib/caffeinate/version.rb
177
177
  - lib/generators/caffeinate/install_generator.rb
178
+ - lib/generators/caffeinate/mailer_generator.rb
178
179
  - lib/generators/caffeinate/templates/application_dripper.rb
179
180
  - lib/generators/caffeinate/templates/caffeinate.rb
181
+ - lib/generators/caffeinate/templates/mailer.rb.tt
180
182
  - lib/generators/caffeinate/views_generator.rb
181
183
  homepage: https://github.com/joshmn/caffeinate
182
184
  licenses: