Class: MailyHerald::PeriodicalMailing

Inherits:
Mailing
  • Object
show all
Defined in:
app/models/maily_herald/periodical_mailing.rb

Instance Attribute Summary

Attributes inherited from Dispatch

#absolute_delay, #conditions, #from, #list_id, #mailer_name, #name, #override_subscription, #period, #sequence_id, #state, #subject, #template, #title, #type

Instance Method Summary collapse

Methods inherited from Mailing

#ad_hoc?, #build_mail, #conditions, #conditions=, #conditions_changed?, #conditions_met?, #destination, #general_scheduling?, #generic_mailer?, #has_conditions?, #has_conditions_proc?, #individual_scheduling?, #mailer, #mailer_name, #one_time?, #periodical?, #render_subject, #render_template, #sequence?, #test_conditions

Methods included from Autonaming

included

Methods included from TemplateRenderer

included

Methods inherited from Dispatch

#archive, #archive!, #archived?, #disable, #disable!, #disabled?, #enable, #enable!, #enabled?, #has_start_at_proc?, #in_scope?, #list=, #locked?, #processable?, #start_at, #start_at=, #start_at_changed?, #subscription_valid?

Instance Method Details

#calculate_processing_time(entity, last_log = nil) ⇒ Object

Calculates processing time for given entity.



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'app/models/maily_herald/periodical_mailing.rb', line 125

def calculate_processing_time entity, last_log = nil
  last_log ||= processed_logs(entity).last

  spt = start_processing_time(entity)

  if last_log && last_log.processing_at
    last_log.processing_at + self.period
  elsif individual_scheduling? && spt
    spt
  elsif general_scheduling?
    if spt >= Time.now
      spt
    else
      diff = (Time.now - spt).to_f
      spt ? spt + ((diff/self.period).ceil * self.period) : nil
    end
  else
    nil
  end
end

#last_processing_time(entity) ⇒ Object

Gets the timestamp of last processed email for given entity.



68
69
70
# File 'app/models/maily_herald/periodical_mailing.rb', line 68

def last_processing_time entity
  processed_logs(entity).last.try(:processing_at)
end

#next_processing_time(entity) ⇒ Object

Get next email processing time for given entity.



147
148
149
# File 'app/models/maily_herald/periodical_mailing.rb', line 147

def next_processing_time entity
  schedule_for(entity).processing_at
end

#period_in_daysObject



13
14
15
# File 'app/models/maily_herald/periodical_mailing.rb', line 13

def period_in_days
  "%.2f" % (self.period.to_f / 1.day.seconds)
end

#period_in_days=(d) ⇒ Object



16
17
18
# File 'app/models/maily_herald/periodical_mailing.rb', line 16

def period_in_days= d
  self.period = d.to_f.days
end

#processed_logs(entity) ⇒ Object

Returns collection of processed Logs for given entity.



42
43
44
# File 'app/models/maily_herald/periodical_mailing.rb', line 42

def processed_logs entity
  Log.ordered.for_entity(entity).for_mailing(self).processed
end

#runObject

Sends mailing to all subscribed entities.

Performs actual sending of emails; should be called in background.

Returns array of Log with actual `Mail::Message` objects stored in Log.mail attributes.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'app/models/maily_herald/periodical_mailing.rb', line 26

def run
  # TODO better scope here to exclude schedules for users outside context scope
  schedules.where("processing_at <= (?)", Time.now).collect do |schedule|
    if schedule.entity
      mail = deliver schedule
      schedule.reload
      schedule.mail = mail
      schedule
    else
      MailyHerald.logger.log_processing(schedule.mailing, {class: schedule.entity_type, id: schedule.entity_id}, prefix: "Removing schedule for non-existing entity") 
      schedule.destroy
    end
  end
end

#schedule_for(entity) ⇒ Object

Returns Log object which is the delivery schedule for given entity.



115
116
117
# File 'app/models/maily_herald/periodical_mailing.rb', line 115

def schedule_for entity
  schedules.for_entity(entity).first
end

#schedulesObject

Returns collection of all delivery schedules (Log collection).



120
121
122
# File 'app/models/maily_herald/periodical_mailing.rb', line 120

def schedules
  Log.ordered.scheduled.for_mailing(self)
end

#set_schedule_for(entity, last_log = nil) ⇒ Object

Sets the delivery schedule for given entity

New schedule will be created or existing one updated.

Schedule is Log object of type “schedule”.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'app/models/maily_herald/periodical_mailing.rb', line 77

def set_schedule_for entity, last_log = nil
  subscribed = self.list.subscribed?(entity)
  log = schedule_for(entity)
  last_log ||= processed_logs(entity).last
  processing_at = calculate_processing_time(entity, last_log)

  if !self.period || !self.start_at || !enabled? || !processing_at || !(self.override_subscription? || subscribed)
    log = schedule_for(entity)
    log.try(:destroy)
    return
  end

  log ||= Log.new
  log.with_lock do
    log.set_attributes_for(self, entity, {
      status: :scheduled,
      processing_at: processing_at,
    })
    log.save!
  end
  log
end

#set_schedulesObject

Sets delivery schedules of all entities in mailing scope.

New schedules will be created or existing ones updated.



103
104
105
106
107
108
# File 'app/models/maily_herald/periodical_mailing.rb', line 103

def set_schedules
  self.list.context.scope_with_subscription(self.list, :outer).each do |entity|
    MailyHerald.logger.debug "Updating schedule of #{self} periodical for entity ##{entity.id} #{entity}"
    set_schedule_for entity
  end
end

#start_processing_time(entity) ⇒ Object

Returns processing time for given entity.

This is the time when next mailing should be sent. Calculation is done mased on last processed mailing for this entity or Dispatch#start_at mailing attribute.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'app/models/maily_herald/periodical_mailing.rb', line 51

def start_processing_time entity
  if processed_logs(entity).first
    processed_logs(entity).first.processing_at
  else
    subscription = self.list.subscription_for(entity)

    if has_start_at_proc?
      start_at.call(entity, subscription)
    else
      evaluator = Utils::MarkupEvaluator.new(self.list.context.drop_for(entity, subscription))

      evaluator.evaluate_start_at(self.start_at)
    end
  end
end

#to_sObject



151
152
153
# File 'app/models/maily_herald/periodical_mailing.rb', line 151

def to_s
  "<PeriodicalMailing: #{self.title || self.name}>"
end

#update_schedules_callbackObject



110
111
112
# File 'app/models/maily_herald/periodical_mailing.rb', line 110

def update_schedules_callback
  Rails.env.test? ? set_schedules : MailyHerald::ScheduleUpdater.perform_in(10.seconds, self.id)
end