completed SMS gateway project
This commit is contained in:
110
app/models/sms_message.rb
Normal file
110
app/models/sms_message.rb
Normal file
@@ -0,0 +1,110 @@
|
||||
class SmsMessage < ApplicationRecord
|
||||
# Normalize metadata to always be a Hash
|
||||
attribute :metadata, :jsonb, default: {}
|
||||
|
||||
belongs_to :gateway, optional: true
|
||||
|
||||
validates :phone_number, presence: true
|
||||
validates :message_body, presence: true, length: { maximum: 1600 }
|
||||
validates :direction, presence: true, inclusion: { in: %w[inbound outbound] }
|
||||
validates :message_id, presence: true, uniqueness: true
|
||||
validates :status, inclusion: { in: %w[pending queued sent delivered failed] }
|
||||
|
||||
validate :phone_number_format
|
||||
|
||||
before_validation :ensure_metadata_is_hash
|
||||
before_validation :generate_message_id, on: :create
|
||||
before_validation :normalize_phone_number
|
||||
after_create_commit :enqueue_sending, if: :outbound?
|
||||
|
||||
scope :pending, -> { where(status: "pending") }
|
||||
scope :queued, -> { where(status: "queued") }
|
||||
scope :sent, -> { where(status: "sent") }
|
||||
scope :delivered, -> { where(status: "delivered") }
|
||||
scope :failed, -> { where(status: "failed") }
|
||||
scope :inbound, -> { where(direction: "inbound") }
|
||||
scope :outbound, -> { where(direction: "outbound") }
|
||||
scope :recent, -> { order(created_at: :desc) }
|
||||
|
||||
# Check message direction
|
||||
def outbound?
|
||||
direction == "outbound"
|
||||
end
|
||||
|
||||
def inbound?
|
||||
direction == "inbound"
|
||||
end
|
||||
|
||||
# Check if message can be retried
|
||||
def can_retry?
|
||||
failed? && retry_count < 3
|
||||
end
|
||||
|
||||
# Mark message as sent
|
||||
def mark_sent!(gateway)
|
||||
update!(
|
||||
status: "sent",
|
||||
gateway: gateway,
|
||||
sent_at: Time.current
|
||||
)
|
||||
gateway.increment_sent_count!
|
||||
end
|
||||
|
||||
# Mark message as delivered
|
||||
def mark_delivered!
|
||||
update!(
|
||||
status: "delivered",
|
||||
delivered_at: Time.current
|
||||
)
|
||||
end
|
||||
|
||||
# Mark message as failed
|
||||
def mark_failed!(error_msg = nil)
|
||||
update!(
|
||||
status: "failed",
|
||||
failed_at: Time.current,
|
||||
error_message: error_msg
|
||||
)
|
||||
end
|
||||
|
||||
# Increment retry counter
|
||||
def increment_retry!
|
||||
increment!(:retry_count)
|
||||
end
|
||||
|
||||
# Check if message status is failed
|
||||
def failed?
|
||||
status == "failed"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_message_id
|
||||
self.message_id ||= "msg_#{SecureRandom.hex(16)}"
|
||||
end
|
||||
|
||||
def normalize_phone_number
|
||||
return unless phone_number.present?
|
||||
|
||||
# Remove spaces and special characters
|
||||
self.phone_number = phone_number.gsub(/[^\d+]/, "")
|
||||
end
|
||||
|
||||
def phone_number_format
|
||||
return unless phone_number.present?
|
||||
|
||||
phone = Phonelib.parse(phone_number)
|
||||
unless phone.valid?
|
||||
errors.add(:phone_number, "is not a valid phone number")
|
||||
end
|
||||
end
|
||||
|
||||
def enqueue_sending
|
||||
SendSmsJob.perform_later(id)
|
||||
end
|
||||
|
||||
def ensure_metadata_is_hash
|
||||
self.metadata = {} if metadata.nil?
|
||||
self.metadata = {} unless metadata.is_a?(Hash)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user