app/models/voltron/notification/sms_notification.rb in voltron-notify-0.1.9 vs app/models/voltron/notification/sms_notification.rb in voltron-notify-0.2.0

- old
+ new

@@ -8,13 +8,15 @@ belongs_to :notification after_initialize :setup - before_create :deliver_now, unless: :use_queue? + before_create :send_now, unless: :use_queue? - after_create :deliver_later, if: :use_queue? + # We have a separate check for +created+ because we trigger +save+ within this callback, + # and there are known issues of recursion when that is the case. See: https://github.com/rails/rails/issues/14493 + after_commit :send_later, on: :create, if: Proc.new { |n| n.send(:use_queue?) && !n.created } validates :status, presence: false, inclusion: { in: %w( accepted queued sending sent delivered received failed undelivered unknown ), message: I18n.t('voltron.notification.sms.status_invalid') }, on: :update validates_presence_of :to, message: I18n.t('voltron.notification.sms.to_blank') @@ -22,64 +24,30 @@ validates_presence_of :message, message: I18n.t('voltron.notification.sms.message_blank') validate :valid_phone_number - def setup - @request = [] - @response = [] - end + attr_accessor :created def request - # Ensure returned object is an array of request hashes, for consistency - out = Array.wrap((JSON.parse(request_json) rescue nil)).compact - out.map { |h| h.with_indifferent_access } + Voltron::Notification.format_output_of(request_json) end def response - # Ensure returned object is an array of response hashes, for consistency - out = Array.wrap((JSON.parse(response_json) rescue nil)).compact - out.map { |h| h.with_indifferent_access } + Voltron::Notification.format_output_of(response_json) end - def after_deliver - self.request_json = @request.to_json - self.response_json = @response.to_json - self.sid = response.first.try(:[], :sid) - self.status = response.first.try(:[], :status) || 'unknown' - - # if use_queue?, meaning if this was sent via ActiveJob, we need to save ourself - # since we got to here within after_create, meaning setting the attributes alone won't cut it - self.save if use_queue? - end - + # Establish that we will perform the job immediately. Will cause +send_now+ to be called instead when saved def deliver_now - @request = request - @response = response - - all_attachments = attachments.map(&:attachment) - - # If sending more than 1 attachment, iterate through all but one attachment and send each without a body... - if all_attachments.count > 1 - begin - client.messages.create({ from: from_formatted, to: to_formatted, media_url: all_attachments.shift, status_callback: callback_url }.compact) - @request << Rack::Utils.parse_nested_query(client.last_request.body) - @response << JSON.parse(client.last_response.body) - end until all_attachments.count == 1 - end - - # ... Then send the last attachment (if any) with the actual text body. This way we're not sending multiple SMS's with same body - client.messages.create({ from: from_formatted, to: to_formatted, body: message, media_url: all_attachments.shift, status_callback: callback_url }.compact) - @request << Rack::Utils.parse_nested_query(client.last_request.body) - @response << JSON.parse(client.last_response.body) - after_deliver + @job_options = {} + @job_method = :perform_now end - def deliver_later - job = Voltron::SmsJob.set(wait: Voltron.config.notify.delay).perform_later self - @request << job - after_deliver + # Establish that the job should be enqueued, and set the options + def deliver_later(options={}) + @job_options = options + @job_method = :perform_later end def attach(*urls) urls.flatten.each do |url| if url.starts_with? 'http' @@ -90,37 +58,97 @@ end end def valid_phone? begin - return true if to.blank? # Handle a blank `to` separately in the errors method below to_formatted true rescue => e Voltron.log e.message, 'Notify', Voltron::Notify::LOG_COLOR false end end - def callback_url - url = try(:update_voltron_notification_url, host: Voltron.config.base_url).to_s - # Don't allow local or blank urls - return nil if url.include?('localhost') || url.include?('127.0.0.1') || url.blank? - url - end - private + # Sends the SMS message + def send_now + @request = request + @response = response + + all_attachments = attachments.map(&:attachment) + + # If sending more than 1 attachment, iterate through all but one attachment and send each without a body... + if all_attachments.count > 1 + loop do + break if all_attachments.count == 1 + client.messages.create({ from: from_formatted, to: to_formatted, media_url: all_attachments.shift, status_callback: callback_url }.compact) + @request << Rack::Utils.parse_nested_query(client.last_request.body) + @response << JSON.parse(client.last_response.body) + end + end + + # ... Then send the last attachment (if any) with the actual text body. This way we're not sending multiple SMS's with same body + client.messages.create({ from: from_formatted, to: to_formatted, body: message, media_url: all_attachments.shift, status_callback: callback_url }.compact) + @request << Rack::Utils.parse_nested_query(client.last_request.body) + @response << JSON.parse(client.last_response.body) + after_deliver + end + + # Enqueue a job to deliver the SMS message, with options defined by calls to +deliver_later+ + def send_later + @request << Voltron::SmsJob.set(default_options.merge(job_options)).send(job_method, self) + after_deliver + end + + def setup + @request = [] + @response = [] + end + + def job_options + @job_options ||= {} + end + + def job_method + @job_method ||= :perform_later + end + + def default_options + notification.notifyable.class.instance_variable_get('@_notification_defaults').try(:[], :sms) || {} + end + + def after_deliver + @created = true + @job_options = nil + @job_method = nil + self.request_json = @request.to_json + self.response_json = @response.to_json + self.sid = response.first.try(:[], :sid) + self.status = response.first.try(:[], :status) || 'unknown' + + # if use_queue?, meaning if this was sent via ActiveJob, we need to save ourself + # since we got to here within after_create, meaning setting the attributes alone won't cut it + self.save if use_queue? + end + + def callback_url + url = try(:update_voltron_notification_url, host: Voltron.config.base_url).to_s + # Don't allow local or blank urls + return nil if url.include?('localhost') || url.include?('127.0.0.1') || url.blank? + url + end + def valid_phone_number errors.add :to, I18n.t('voltron.notification.sms.invalid_phone', number: to) unless valid_phone? end def use_queue? Voltron.config.notify.use_queue end def to_formatted - format to + format to || notification.notifyable.try(:phone) end def from_formatted format from end