200 lines
5.4 KiB
Ruby
200 lines
5.4 KiB
Ruby
module JamRuby
|
|
class EmailBatch < ActiveRecord::Base
|
|
self.table_name = "email_batches"
|
|
|
|
has_many :email_batch_sets, :class_name => 'JamRuby::EmailBatchSet'
|
|
|
|
attr_accessible :from_email, :subject, :test_emails, :body
|
|
attr_accessible :lock_version, :opt_in_count, :sent_count, :started_at, :completed_at
|
|
|
|
default_scope :order => 'created_at DESC'
|
|
|
|
VAR_FIRST_NAME = '@FIRSTNAME'
|
|
VAR_LAST_NAME = '@LASTNAME'
|
|
|
|
DEFAULT_SENDER = "support@jamkazam.com"
|
|
BATCH_SIZE = 1000
|
|
|
|
BODY_TEMPLATE =<<FOO
|
|
Hello #{VAR_FIRST_NAME},
|
|
|
|
<p>Paragraph 1 ... newline whitespace is significant for plain text conversions</p>
|
|
|
|
<p>Paragraph 2 ... "#{VAR_FIRST_NAME}" will be replaced by users first name</p>
|
|
|
|
<p>Thanks for using JamKazam!</p>
|
|
FOO
|
|
|
|
include AASM
|
|
aasm do
|
|
state :pending, :initial => true
|
|
state :testing
|
|
state :tested
|
|
state :delivering
|
|
state :delivered
|
|
state :disabled
|
|
|
|
event :enable do
|
|
transitions :from => :disabled, :to => :pending
|
|
end
|
|
event :reset, :after => :did_reset do
|
|
transitions :from => [:disabled, :testing, :tested, :delivering, :delivered, :pending], :to => :pending
|
|
end
|
|
event :do_test_run, :before => :will_run_tests do
|
|
transitions :from => [:pending, :tested, :delivered], :to => :testing
|
|
end
|
|
event :did_test_run, :after => :ran_tests do
|
|
transitions :from => :testing, :to => :tested
|
|
end
|
|
event :do_batch_run, :before => :will_run_batch do
|
|
transitions :from => [:tested, :pending, :delivered], :to => :delivering
|
|
end
|
|
event :did_batch_run, :after => :ran_batch do
|
|
transitions :from => :delivering, :to => :delivered
|
|
end
|
|
event :disable do
|
|
transitions :from => [:pending, :tested, :delivered], :to => :disabled
|
|
end
|
|
end
|
|
|
|
def self.new(*args)
|
|
oo = super
|
|
oo.body = BODY_TEMPLATE
|
|
oo
|
|
end
|
|
|
|
def self.create_with_params(params)
|
|
obj = self.new
|
|
params.each { |kk,vv| vv.strip! }
|
|
obj.update_with_conflict_validation(params)
|
|
obj
|
|
end
|
|
|
|
def can_run_batch?
|
|
self.tested? || self.pending?
|
|
end
|
|
|
|
def can_run_test?
|
|
self.test_emails.present? && (self.tested? || self.pending?)
|
|
end
|
|
|
|
def deliver_batch
|
|
self.perform_event('do_batch_run!')
|
|
User.email_opt_in.find_in_batches(batch_size: BATCH_SIZE) do |users|
|
|
self.email_batch_sets << EmailBatchSet.deliver_set(self.id, users.map(&:id))
|
|
end
|
|
end
|
|
|
|
def test_count
|
|
self.test_emails.split(',').count
|
|
end
|
|
|
|
def test_users
|
|
self.test_emails.split(',').collect do |ee|
|
|
ee.strip!
|
|
uu = User.new
|
|
uu.email = ee
|
|
uu.first_name = ee.match(/^(.*)@/)[1].to_s
|
|
uu.last_name = 'Test'
|
|
uu
|
|
end
|
|
end
|
|
|
|
def send_test_batch
|
|
self.perform_event('do_test_run!')
|
|
if 'test'==Rails.env
|
|
BatchMailer.send_batch_email_test(self.id).deliver!
|
|
else
|
|
BatchMailer.send_batch_email_test(self.id).deliver
|
|
end
|
|
end
|
|
|
|
def merged_body(user)
|
|
body.gsub(VAR_FIRST_NAME, user.first_name).gsub(VAR_LAST_NAME, user.last_name)
|
|
end
|
|
|
|
def did_send(emails)
|
|
self.update_with_conflict_validation({ :sent_count => self.sent_count + emails.size })
|
|
|
|
if self.sent_count >= self.opt_in_count
|
|
if delivering?
|
|
self.perform_event('did_batch_run!')
|
|
elsif testing?
|
|
self.perform_event('did_test_run!')
|
|
end
|
|
end
|
|
end
|
|
|
|
def perform_event(event_name)
|
|
num_try = 0
|
|
self.send(event_name)
|
|
rescue ActiveRecord::StaleObjectError
|
|
num_try += 1
|
|
if 5 > num_try
|
|
self.reload
|
|
retry
|
|
end
|
|
end
|
|
|
|
def update_with_conflict_validation(*args)
|
|
num_try = 0
|
|
begin
|
|
update_attributes(*args)
|
|
rescue ActiveRecord::StaleObjectError
|
|
num_try += 1
|
|
if 5 > num_try
|
|
self.reload
|
|
sleep(0.25)
|
|
retry
|
|
end
|
|
end
|
|
end
|
|
|
|
def will_run_batch
|
|
self.update_with_conflict_validation({:opt_in_count => User.email_opt_in.count,
|
|
:sent_count => 0,
|
|
:started_at => Time.now
|
|
})
|
|
end
|
|
|
|
def will_run_tests
|
|
self.update_with_conflict_validation({:opt_in_count => self.test_count,
|
|
:sent_count => 0
|
|
})
|
|
end
|
|
|
|
def ran_tests
|
|
self.update_with_conflict_validation({ :completed_at => Time.now })
|
|
end
|
|
|
|
def ran_batch
|
|
self.update_with_conflict_validation({ :completed_at => Time.now })
|
|
end
|
|
|
|
def clone
|
|
bb = EmailBatch.new
|
|
bb.subject = self.subject
|
|
bb.body = self.body
|
|
bb.from_email = self.from_email
|
|
bb.test_emails = self.test_emails
|
|
bb.save!
|
|
bb
|
|
end
|
|
|
|
def opting_in_count
|
|
0 < opt_in_count ? opt_in_count : User.email_opt_in.count
|
|
end
|
|
|
|
def did_reset
|
|
self.email_batch_sets.map(&:destroy)
|
|
self.update_with_conflict_validation({
|
|
:opt_in_count => 0,
|
|
:sent_count => 0,
|
|
:started_at => nil,
|
|
:completed_at => nil,
|
|
})
|
|
end
|
|
|
|
end
|
|
end
|