Repository: chatwoot/chatwoot
File: app/models/message.rb (Ruby)

Code before:
    #   - Adding an extra feature flag here would cause confusion.
    #   - If the user has configured Elasticsearch, enabling `advanced_search`
    #     should automatically work without any additional flags.
    return false if ChatwootApp.chatwoot_cloud? && !account.feature_enabled?('advanced_search_indexing')

    true
  end

  private

  def flatten_custom_attributes(attrs)
    return [] if attrs.blank?

    attrs.map do |key, value|
      {
        key: key.to_s,
        value: value.to_s,

        value_type: value.class.name.downcase
      }
    end
  end

  def search_attachments_data
    attachments.filter_map do |a|
      { transcribed_text: a.meta&.dig('transcribed_text') }
    end.presence
  end

  def search_content_attributes_data
    {
      email: {
        subject: content_attributes.dig(:email, :subject) || content_attributes.dig('email', 'subject')
      }.compact
    }.compact
  end

  def search_conversation_data
    return nil unless conversation

    {
      id: conversation.id,
      display_id: conversation.display_id,
      status: conversation.status,
      assignee_id: conversation.assignee_id,
      team_id: conversation.team_id,
      contact_id: conversation.contact_id,
      custom_attributes: flatten_custom_attributes(conversation.custom_attributes),
      browser: conversation.additional_attributes&.dig('browser'),
      referer: conversation.additional_attributes&.dig('referer'),
      initated_at: conversation.additional_attributes&.dig('initated_at')

Review comment (suggestion):
`transcribed_text` would be `nil` for most of the messages. Should we create the field only if `transcribed_text.present?` 

Code after:
  end

  def ensure_processed_message_content
    text_content_quoted = content_attributes.dig(:email, :text_content, :quoted)
    html_content_quoted = content_attributes.dig(:email, :html_content, :quoted)

    message_content = text_content_quoted || html_content_quoted || content
    self.processed_message_content = message_content&.truncate(150_000)
  end

  # fetch the in_reply_to message and set the external id
  def ensure_in_reply_to
    in_reply_to = content_attributes[:in_reply_to]
    in_reply_to_external_id = content_attributes[:in_reply_to_external_id]

    Messages::InReplyToMessageBuilder.new(
      message: self,
      in_reply_to: in_reply_to,
      in_reply_to_external_id: in_reply_to_external_id
    ).perform
  end

  def ensure_content_type
    self.content_type ||= Message.content_types[:text]
  end

  def execute_after_create_commit_callbacks
    # rails issue with order of active record callbacks being executed https://github.com/rails/rails/issues/20911
    reopen_conversation
    set_conversation_activity
    dispatch_create_events
    send_reply
    execute_message_template_hooks
    update_contact_activity
  end

  def update_contact_activity
    sender.update(last_activity_at: DateTime.now) if sender.is_a?(Contact)
  end

  def update_waiting_since
    if human_response? && !private && conversation.waiting_since.present?
      Rails.configuration.dispatcher.dispatch(
        REPLY_CREATED, Time.zone.now, waiting_since: conversation.waiting_since, message: self
      )
      conversation.update(waiting_since: nil)
    end
    conversation.update(waiting_since: created_at) if incoming? && conversation.waiting_since.blank?
  end

  def human_response?