2021-04-29 16:53:32 +00:00
|
|
|
# == Schema Information
|
|
|
|
#
|
|
|
|
# Table name: campaigns
|
|
|
|
#
|
2021-10-12 12:28:33 +00:00
|
|
|
# id :bigint not null, primary key
|
|
|
|
# audience :jsonb
|
|
|
|
# campaign_status :integer default("active"), not null
|
|
|
|
# campaign_type :integer default("ongoing"), not null
|
|
|
|
# description :text
|
|
|
|
# enabled :boolean default(TRUE)
|
|
|
|
# message :text not null
|
|
|
|
# scheduled_at :datetime
|
|
|
|
# title :string not null
|
|
|
|
# trigger_only_during_business_hours :boolean default(FALSE)
|
|
|
|
# trigger_rules :jsonb
|
|
|
|
# created_at :datetime not null
|
|
|
|
# updated_at :datetime not null
|
|
|
|
# account_id :bigint not null
|
|
|
|
# display_id :integer not null
|
|
|
|
# inbox_id :bigint not null
|
|
|
|
# sender_id :integer
|
2021-04-29 16:53:32 +00:00
|
|
|
#
|
|
|
|
# Indexes
|
|
|
|
#
|
2021-07-14 06:54:09 +00:00
|
|
|
# index_campaigns_on_account_id (account_id)
|
|
|
|
# index_campaigns_on_campaign_status (campaign_status)
|
|
|
|
# index_campaigns_on_campaign_type (campaign_type)
|
|
|
|
# index_campaigns_on_inbox_id (inbox_id)
|
|
|
|
# index_campaigns_on_scheduled_at (scheduled_at)
|
2021-04-29 16:53:32 +00:00
|
|
|
#
|
|
|
|
# Foreign Keys
|
|
|
|
#
|
2021-12-19 04:17:07 +00:00
|
|
|
# fk_rails_... (account_id => accounts.id) ON DELETE => cascade
|
|
|
|
# fk_rails_... (inbox_id => inboxes.id) ON DELETE => cascade
|
2021-04-29 16:53:32 +00:00
|
|
|
#
|
2022-02-04 09:08:18 +00:00
|
|
|
require 'uri'
|
2021-04-29 16:53:32 +00:00
|
|
|
class Campaign < ApplicationRecord
|
|
|
|
validates :account_id, presence: true
|
|
|
|
validates :inbox_id, presence: true
|
2021-04-30 13:15:24 +00:00
|
|
|
validates :title, presence: true
|
|
|
|
validates :message, presence: true
|
2021-07-14 06:54:09 +00:00
|
|
|
validate :validate_campaign_inbox
|
2022-02-04 09:08:18 +00:00
|
|
|
validate :validate_url
|
2021-07-14 06:54:09 +00:00
|
|
|
validate :prevent_completed_campaign_from_update, on: :update
|
2021-04-29 16:53:32 +00:00
|
|
|
belongs_to :account
|
|
|
|
belongs_to :inbox
|
|
|
|
belongs_to :sender, class_name: 'User', optional: true
|
|
|
|
|
2021-07-14 06:54:09 +00:00
|
|
|
enum campaign_type: { ongoing: 0, one_off: 1 }
|
|
|
|
# TODO : enabled attribute is unneccessary . lets move that to the campaign status with additional statuses like draft, disabled etc.
|
|
|
|
enum campaign_status: { active: 0, completed: 1 }
|
|
|
|
|
2021-04-29 16:53:32 +00:00
|
|
|
has_many :conversations, dependent: :nullify, autosave: true
|
|
|
|
|
2021-07-14 06:54:09 +00:00
|
|
|
before_validation :ensure_correct_campaign_attributes
|
2021-04-29 16:53:32 +00:00
|
|
|
after_commit :set_display_id, unless: :display_id?
|
|
|
|
|
2021-07-14 06:54:09 +00:00
|
|
|
def trigger!
|
|
|
|
return unless one_off?
|
|
|
|
return if completed?
|
|
|
|
|
|
|
|
Twilio::OneoffSmsCampaignService.new(campaign: self).perform if inbox.inbox_type == 'Twilio SMS'
|
2022-02-03 23:22:13 +00:00
|
|
|
Sms::OneoffSmsCampaignService.new(campaign: self).perform if inbox.inbox_type == 'Sms'
|
2021-07-14 06:54:09 +00:00
|
|
|
end
|
|
|
|
|
2021-04-29 16:53:32 +00:00
|
|
|
private
|
|
|
|
|
|
|
|
def set_display_id
|
|
|
|
reload
|
|
|
|
end
|
|
|
|
|
2021-07-14 06:54:09 +00:00
|
|
|
def validate_campaign_inbox
|
|
|
|
return unless inbox
|
|
|
|
|
2022-02-03 23:22:13 +00:00
|
|
|
errors.add :inbox, 'Unsupported Inbox type' unless ['Website', 'Twilio SMS', 'Sms'].include? inbox.inbox_type
|
2021-07-14 06:54:09 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# TO-DO we clean up with better validations when campaigns evolve into more inboxes
|
|
|
|
def ensure_correct_campaign_attributes
|
|
|
|
return if inbox.blank?
|
|
|
|
|
2022-02-03 23:22:13 +00:00
|
|
|
if ['Twilio SMS', 'Sms'].include?(inbox.inbox_type)
|
2021-07-14 06:54:09 +00:00
|
|
|
self.campaign_type = 'one_off'
|
|
|
|
self.scheduled_at ||= Time.now.utc
|
|
|
|
else
|
|
|
|
self.campaign_type = 'ongoing'
|
|
|
|
self.scheduled_at = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-02-04 09:08:18 +00:00
|
|
|
def validate_url
|
|
|
|
return unless trigger_rules['url']
|
|
|
|
|
|
|
|
errors.add(:url, 'invalid') if inbox.inbox_type == 'Website' && !url_valid?(trigger_rules['url'])
|
|
|
|
end
|
|
|
|
|
|
|
|
def url_valid?(url)
|
|
|
|
url = begin
|
|
|
|
URI.parse(url)
|
|
|
|
rescue StandardError
|
|
|
|
false
|
|
|
|
end
|
|
|
|
url.is_a?(URI::HTTP) || url.is_a?(URI::HTTPS)
|
|
|
|
end
|
|
|
|
|
2021-07-14 06:54:09 +00:00
|
|
|
def prevent_completed_campaign_from_update
|
|
|
|
errors.add :status, 'The campaign is already completed' if !campaign_status_changed? && completed?
|
|
|
|
end
|
|
|
|
|
2021-04-29 16:53:32 +00:00
|
|
|
# creating db triggers
|
|
|
|
trigger.before(:insert).for_each(:row) do
|
|
|
|
"NEW.display_id := nextval('camp_dpid_seq_' || NEW.account_id);"
|
|
|
|
end
|
|
|
|
end
|