|
class Message < ActiveRecord::Base |
|
belongs_to :user |
|
has_many :replies |
|
has_and_belongs_to_many :applicant_recipients, :join_table => :message_recipients, :class_name => "Applicant" |
|
has_and_belongs_to_many :user_recipients, :join_table => :message_recipients, :class_name => "User" |
|
|
|
def deliver_message(params) |
|
# If message is not part of a current thread, create new thread with message as thread root |
|
update_attribute(:thread_root_id, id) if thread_root_id.nil? |
|
populate_recipients(params) |
|
# If no scheduled time present, send and broadcast message now and update recipient attributes accordingly |
|
unless scheduled_time.present? |
|
broadcast and send_now |
|
transition_applicant_recipients |
|
else |
|
# If scheduled time present, schedule job for time specified |
|
schedule_job |
|
end |
|
end |
|
|
|
# Determine message recipients based on message params |
|
def populate_recipients(params) |
|
applicant_ids, user_ids, = nil, nil |
|
if params.group_type |
|
case params.group_type |
|
when "applicants" |
|
if params.message_all == "true" |
|
applicant_ids = Applicant.active.pluck(:id) |
|
elsif params.group_ids.present? |
|
# Collect ids for applicants in applicant groups |
|
groups = Group.where(id: params.group_ids.map(&:to_i)).includes(:applicants) |
|
group_ids = groups.pluck(:id) |
|
# Collect unique ids in event applicant belongs to multiple groups (to avoid duplicate messages) |
|
applicant_ids = groups.collect { |group| group.applicants.pluck(:id) }.flatten.uniq |
|
elsif params.individual_ids.present? |
|
applicant_ids = params.individual_ids.split(",").reject(&:empty?).map(&:to_i) |
|
end |
|
when "users" |
|
if params.message_all == "true" |
|
user_ids = User.staff.pluck(:id) |
|
elsif params.individual_ids.present? |
|
user_ids = params.individual_ids.split(",").reject(&:empty?).map(&:to_i) |
|
end |
|
end |
|
end |
|
|
|
insert_recipients(applicant_ids, user_ids) |
|
end |
|
|
|
# Populate message_recipients join table for applicants, applicant groups, and users |
|
def insert_recipients(applicant_ids, user_ids) |
|
message_id, inserts = self.id, [] |
|
# Collect inserts for mass db write |
|
applicant_ids.each { |id| inserts.push "(#{message_id}, #{id}, NULL)" } unless applicant_ids.nil? |
|
user_ids.each { |id| inserts.push "(#{message_id}, NULL, #{id})" } unless user_ids.nil? |
|
# Use SQL inserts to speed up mass writes |
|
MessageRecipient.connection.execute("INSERT INTO message_recipients (message_id, applicant_id, user_id) VALUES #{inserts.join(',')}") |
|
end |
|
|
|
# When applicant is messaged, update last_contact and clear reply_rcvd |
|
def transition_applicant_recipients |
|
self.applicant_recipients.update_all(last_contacted: Time.now, reply_rcvd: nil) if self.applicant_recipients.present? |
|
end |
|
|
|
def broadcast |
|
# Define websocket data to push to clients connected to sms_channel |
|
message_data = { |
|
:id => id, |
|
:message_type => message_type, |
|
:thread_root_id => thread_root_id, |
|
:reply_ref_id => reply_ref_id, |
|
:user => user, |
|
:body => body, |
|
:created_at_formatted => created_at.in_time_zone(SettingsDetail.first.timezone).strftime("%A, %B %e, %Y at %l:%M %P %Z"), |
|
:recipients => recipient_data_for_broadcast |
|
} |
|
# Broadcast "new_message" event on "sms_channel" |
|
WebsocketRails[:sms_channel].trigger(:new_message, message_data) |
|
end |
|
|
|
def send_now |
|
job = SmsWorkers::StandardMessage.perform_async(id) |
|
update_attributes(sent: Time.now.utc, job_id: job) |
|
end |
|
|
|
def schedule_job |
|
job = SmsWorkers::ScheduledMessage.perform_at(scheduled_time.to_time.utc, id) |
|
update_attribute(:job_id, job) |
|
end |
|
|
|
# Delete old job and reschedule new one |
|
def reschedule_job(new_time) |
|
unless new_time.nil? |
|
delete_scheduled_job |
|
update_attribute(:scheduled_time, new_time) |
|
schedule_job |
|
end |
|
end |
|
|
|
# Delete scheduled job from Sidekiq and clear job_id of message |
|
def delete_scheduled_job |
|
message = self |
|
scheduled_queue = Sidekiq::ScheduledSet.new |
|
# jid is a Sidekiq convention for job_id |
|
# Find Sidekiq job with jid matching job_id of message and delete from queue |
|
scheduled_queue.each do |job| |
|
job.delete if job.jid == message.job_id |
|
end |
|
# Clear job_id from message record |
|
update_attribute(:job_id, nil) |
|
end |
|
|
|
# Collect union of applicant and user recipients |
|
# Returns an array of phone numbers |
|
def collect_recipient_numbers |
|
applicant_recipients.collect { |applicant| applicant.unformatted_number } + user_recipients.collect { |user| user.unformatted_number } |
|
end |
|
|
|
# On incoming reply to message, increment reply count by 1 |
|
def increment_reply_count |
|
update_attribute(:reply_count, ((reply_count ||= 0) + 1)) |
|
end |
|
|
|
def sent_to_applicant?(applicant_id) |
|
applicant_recipients.pluck(:id).include?(applicant_id) |
|
end |
|
|
|
# Collect all applicant OR user recipient objects |
|
# Note that either applicant_recipients or user_recipients will be blank |
|
# i.e. a message is only sent to either applicants OR users |
|
# Thus, regardless of recipient type, the method will return an array of like objects |
|
# (either applicant objects or user objects) |
|
def recipients |
|
applicant_recipients.collect { |applicant| applicant } + user_recipients.collect { |user| user } |
|
end |
|
|
|
def recipient_data_for_broadcast |
|
applicant_recipients.select(["id", "full_name"]) + user_recipients.select(["id", "full_name"]) |
|
end |
|
|
|
# Return collection of thread root messages, i.e. where id == thread_root_id |
|
def self.get_thread_roots |
|
where("id = thread_root_id") |
|
end |
|
|
|
def self.applicant_messages |
|
where("message_type = ? OR message_type = ?", "applicant_msg", "applicant_reg_check") |
|
end |
|
|
|
def self.sent |
|
where("sent IS NOT NULL") |
|
end |
|
|
|
def self.scheduled |
|
where("scheduled_time IS NOT NULL AND sent IS NULL") |
|
end |
|
|
|
def self.search_messages(query) |
|
search_input = "%#{query}%".downcase |
|
where(['LOWER(body) LIKE ?', search_input]) |
|
end |
|
end |
Hello, I noticed that you made a sms api, could direct me to a supplier of SMS shortcode?