mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-03 20:48:07 +00:00 
			
		
		
		
	The term "sorcerer’s apprentice mode" is defined as a bug in a protocol where, under some circumstances, the receipt of a message causes multiple messages to be sent, each of which, when received, triggers the same bug. - RFC3834 Reference: https://github.com/chatwoot/chatwoot/pull/9606 This PR: - Adds an auto_reply attribute to message. - Adds an auto_reply attribute to conversation. - Disable conversation_created / conversation_opened event if auto_reply is set. - Disable message_created event if auto_reply is set. --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
		
			
				
	
	
		
			95 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			95 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
class SupportMailbox < ApplicationMailbox
 | 
						|
  include IncomingEmailValidityHelper
 | 
						|
  attr_accessor :channel, :account, :inbox, :conversation, :processed_mail
 | 
						|
 | 
						|
  before_processing :find_channel,
 | 
						|
                    :load_account,
 | 
						|
                    :load_inbox,
 | 
						|
                    :decorate_mail
 | 
						|
 | 
						|
  def process
 | 
						|
    Rails.logger.info "Processing email #{mail.message_id} from #{original_sender_email} to #{mail.to} with subject #{mail.subject}"
 | 
						|
 | 
						|
    # Skip processing email if it belongs to any of the edge cases
 | 
						|
    return unless incoming_email_from_valid_email?
 | 
						|
 | 
						|
    ActiveRecord::Base.transaction do
 | 
						|
      find_or_create_contact
 | 
						|
      find_or_create_conversation
 | 
						|
      create_message
 | 
						|
      add_attachments_to_message
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  private
 | 
						|
 | 
						|
  def find_channel
 | 
						|
    find_channel_with_to_mail if @channel.blank?
 | 
						|
 | 
						|
    raise 'Email channel/inbox not found' if @channel.nil?
 | 
						|
 | 
						|
    @channel
 | 
						|
  end
 | 
						|
 | 
						|
  def find_channel_with_to_mail
 | 
						|
    @channel = EmailChannelFinder.new(mail).perform
 | 
						|
  end
 | 
						|
 | 
						|
  def load_account
 | 
						|
    @account = @channel.account
 | 
						|
  end
 | 
						|
 | 
						|
  def load_inbox
 | 
						|
    @inbox = @channel.inbox
 | 
						|
  end
 | 
						|
 | 
						|
  def decorate_mail
 | 
						|
    @processed_mail = MailPresenter.new(mail, @account)
 | 
						|
  end
 | 
						|
 | 
						|
  def find_conversation_by_in_reply_to
 | 
						|
    return if in_reply_to.blank?
 | 
						|
 | 
						|
    @account.conversations.where("additional_attributes->>'in_reply_to' = ?", in_reply_to).first
 | 
						|
  end
 | 
						|
 | 
						|
  def in_reply_to
 | 
						|
    mail['In-Reply-To'].try(:value)
 | 
						|
  end
 | 
						|
 | 
						|
  def original_sender_email
 | 
						|
    @processed_mail.original_sender&.downcase
 | 
						|
  end
 | 
						|
 | 
						|
  def find_or_create_conversation
 | 
						|
    @conversation = find_conversation_by_in_reply_to || ::Conversation.create!({
 | 
						|
                                                                                 account_id: @account.id,
 | 
						|
                                                                                 inbox_id: @inbox.id,
 | 
						|
                                                                                 contact_id: @contact.id,
 | 
						|
                                                                                 contact_inbox_id: @contact_inbox.id,
 | 
						|
                                                                                 additional_attributes: {
 | 
						|
                                                                                   in_reply_to: in_reply_to,
 | 
						|
                                                                                   source: 'email',
 | 
						|
                                                                                   auto_reply: @processed_mail.auto_reply?,
 | 
						|
                                                                                   mail_subject: @processed_mail.subject,
 | 
						|
                                                                                   initiated_at: {
 | 
						|
                                                                                     timestamp: Time.now.utc
 | 
						|
                                                                                   }
 | 
						|
                                                                                 }
 | 
						|
                                                                               })
 | 
						|
  end
 | 
						|
 | 
						|
  def find_or_create_contact
 | 
						|
    @contact = @inbox.contacts.from_email(original_sender_email)
 | 
						|
    if @contact.present?
 | 
						|
      @contact_inbox = ContactInbox.find_by(inbox: @inbox, contact: @contact)
 | 
						|
    else
 | 
						|
      create_contact
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def identify_contact_name
 | 
						|
    processed_mail.sender_name || processed_mail.from.first.split('@').first
 | 
						|
  end
 | 
						|
end
 |