Chatwoot/app/models/message.rb
Sony Mathew b803ae3300
Bugfix: Private notes in emails & broken Signup (#1068)
* Bugfix: Private notes in emails

Private notes were sent in the emails as part of
conversation continuity. Fixed this issue.

Also made the changes to not even queue the mails
if message is a private note.

* Bugfix: Change issue with featurable in signup - passing array
* Bugfix: Added specs for checking  private notes being sent in email
2020-07-20 12:47:02 +05:30

167 lines
5.5 KiB
Ruby

# == Schema Information
#
# Table name: messages
#
# id :integer not null, primary key
# content :text
# content_attributes :json
# content_type :integer default("text")
# message_type :integer not null
# private :boolean default(FALSE)
# sender_type :string
# status :integer default("sent")
# created_at :datetime not null
# updated_at :datetime not null
# account_id :integer not null
# conversation_id :integer not null
# inbox_id :integer not null
# sender_id :bigint
# source_id :string
#
# Indexes
#
# index_messages_on_account_id (account_id)
# index_messages_on_conversation_id (conversation_id)
# index_messages_on_inbox_id (inbox_id)
# index_messages_on_sender_type_and_sender_id (sender_type,sender_id)
# index_messages_on_source_id (source_id)
#
class Message < ApplicationRecord
include Events::Types
NUMBER_OF_PERMITTED_ATTACHMENTS = 15
validates :account_id, presence: true
validates :inbox_id, presence: true
validates :conversation_id, presence: true
validates_with ContentAttributeValidator
enum message_type: { incoming: 0, outgoing: 1, activity: 2, template: 3 }
enum content_type: {
text: 0,
input_text: 1,
input_textarea: 2,
input_email: 3,
input_select: 4,
cards: 5,
form: 6,
article: 7,
incoming_email: 8
}
enum status: { sent: 0, delivered: 1, read: 2, failed: 3 }
store :content_attributes, accessors: [:submitted_email, :items, :submitted_values, :email], coder: JSON
# .succ is a hack to avoid https://makandracards.com/makandra/1057-why-two-ruby-time-objects-are-not-equal-although-they-appear-to-be
scope :unread_since, ->(datetime) { where('EXTRACT(EPOCH FROM created_at) > (?)', datetime.to_i.succ) }
scope :chat, -> { where.not(message_type: :activity).where(private: false) }
default_scope { order(created_at: :asc) }
belongs_to :account
belongs_to :inbox
belongs_to :conversation, touch: true
# FIXME: phase out user and contact after 1.4 since the info is there in sender
belongs_to :user, required: false
belongs_to :contact, required: false
belongs_to :sender, polymorphic: true, required: false
has_many :attachments, dependent: :destroy, autosave: true, before_add: :validate_attachments_limit
after_create :reopen_conversation,
:notify_via_mail
after_create_commit :execute_after_create_commit_callbacks
after_update :dispatch_update_event
def channel_token
@token ||= inbox.channel.try(:page_access_token)
end
def push_event_data
data = attributes.merge(
created_at: created_at.to_i,
message_type: message_type_before_type_cast,
conversation_id: conversation.display_id
)
data.merge!(attachments: attachments.map(&:push_event_data)) if attachments.present?
data.merge!(sender: sender.push_event_data) if sender && !sender.is_a?(AgentBot)
data.merge!(sender: sender.push_event_data(inbox)) if sender&.is_a?(AgentBot)
data
end
def reportable?
incoming? || outgoing?
end
def webhook_data
{
id: id,
content: content,
created_at: created_at,
message_type: message_type,
content_type: content_type,
content_attributes: content_attributes,
source_id: source_id,
sender: sender.try(:webhook_data),
inbox: inbox.webhook_data,
conversation: conversation.webhook_data,
account: account.webhook_data
}
end
private
def execute_after_create_commit_callbacks
# rails issue with order of active record callbacks being executed
# https://github.com/rails/rails/issues/20911
dispatch_create_events
send_reply
execute_message_template_hooks
end
def dispatch_create_events
Rails.configuration.dispatcher.dispatch(MESSAGE_CREATED, Time.zone.now, message: self)
if outgoing? && conversation.messages.outgoing.count == 1
Rails.configuration.dispatcher.dispatch(FIRST_REPLY_CREATED, Time.zone.now, message: self)
end
end
def dispatch_update_event
Rails.configuration.dispatcher.dispatch(MESSAGE_UPDATED, Time.zone.now, message: self)
end
def send_reply
::SendReplyJob.perform_later(id)
end
def reopen_conversation
conversation.open! if incoming? && conversation.resolved? && !conversation.muted?
end
def execute_message_template_hooks
::MessageTemplates::HookExecutionService.new(message: self).perform
end
def notify_via_mail
if Redis::Alfred.get(conversation_mail_key).nil? && conversation.contact.email? && outgoing? && !private
# set a redis key for the conversation so that we don't need to send email for every
# new message that comes in and we dont enque the delayed sidekiq job for every message
Redis::Alfred.setex(conversation_mail_key, Time.zone.now)
# Since this is live chat, send the email after few minutes so the only one email with
# last few messages coupled together is sent rather than email for each message
ConversationReplyEmailWorker.perform_in(2.minutes, conversation.id, Time.zone.now)
end
end
def conversation_mail_key
format(::Redis::Alfred::CONVERSATION_MAILER_KEY, conversation_id: conversation.id)
end
def validate_attachments_limit(_attachment)
errors.add(attachments: 'exceeded maximum allowed') if attachments.size >= NUMBER_OF_PERMITTED_ATTACHMENTS
end
end