There are attachments with over 1000 attachments (unusual) in production, and some of them timeout. This PR would limit the number of attachments to 100 (which is sufficient for viewing the files in the gallery, pagination on the UI can be added later).
206 lines
6.1 KiB
Ruby
206 lines
6.1 KiB
Ruby
class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseController
|
|
include Events::Types
|
|
include DateRangeHelper
|
|
include HmacConcern
|
|
|
|
before_action :conversation, except: [:index, :meta, :search, :create, :filter]
|
|
before_action :inbox, :contact, :contact_inbox, only: [:create]
|
|
|
|
ATTACHMENT_RESULTS_PER_PAGE = 100
|
|
|
|
def index
|
|
result = conversation_finder.perform
|
|
@conversations = result[:conversations]
|
|
@conversations_count = result[:count]
|
|
end
|
|
|
|
def meta
|
|
result = conversation_finder.perform
|
|
@conversations_count = result[:count]
|
|
end
|
|
|
|
def search
|
|
result = conversation_finder.perform
|
|
@conversations = result[:conversations]
|
|
@conversations_count = result[:count]
|
|
end
|
|
|
|
def attachments
|
|
@attachments_count = @conversation.attachments.count
|
|
@attachments = @conversation.attachments
|
|
.includes(:message)
|
|
.order(created_at: :desc)
|
|
.page(attachment_params[:page])
|
|
.per(ATTACHMENT_RESULTS_PER_PAGE)
|
|
end
|
|
|
|
def show; end
|
|
|
|
def create
|
|
ActiveRecord::Base.transaction do
|
|
@conversation = ConversationBuilder.new(params: params, contact_inbox: @contact_inbox).perform
|
|
Messages::MessageBuilder.new(Current.user, @conversation, params[:message]).perform if params[:message].present?
|
|
end
|
|
end
|
|
|
|
def update
|
|
@conversation.update!(permitted_update_params)
|
|
end
|
|
|
|
def filter
|
|
result = ::Conversations::FilterService.new(params.permit!, current_user).perform
|
|
@conversations = result[:conversations]
|
|
@conversations_count = result[:count]
|
|
rescue CustomExceptions::CustomFilter::InvalidAttribute,
|
|
CustomExceptions::CustomFilter::InvalidOperator,
|
|
CustomExceptions::CustomFilter::InvalidQueryOperator,
|
|
CustomExceptions::CustomFilter::InvalidValue => e
|
|
render_could_not_create_error(e.message)
|
|
end
|
|
|
|
def mute
|
|
@conversation.mute!
|
|
head :ok
|
|
end
|
|
|
|
def unmute
|
|
@conversation.unmute!
|
|
head :ok
|
|
end
|
|
|
|
def transcript
|
|
render json: { error: 'email param missing' }, status: :unprocessable_entity and return if params[:email].blank?
|
|
|
|
ConversationReplyMailer.with(account: @conversation.account).conversation_transcript(@conversation, params[:email])&.deliver_later
|
|
head :ok
|
|
end
|
|
|
|
def toggle_status
|
|
# FIXME: move this logic into a service object
|
|
if pending_to_open_by_bot?
|
|
@conversation.bot_handoff!
|
|
elsif params[:status].present?
|
|
set_conversation_status
|
|
@status = @conversation.save!
|
|
else
|
|
@status = @conversation.toggle_status
|
|
end
|
|
assign_conversation if should_assign_conversation?
|
|
end
|
|
|
|
def pending_to_open_by_bot?
|
|
return false unless Current.user.is_a?(AgentBot)
|
|
|
|
@conversation.status == 'pending' && params[:status] == 'open'
|
|
end
|
|
|
|
def should_assign_conversation?
|
|
@conversation.status == 'open' && Current.user.is_a?(User) && Current.user&.agent?
|
|
end
|
|
|
|
def toggle_priority
|
|
@conversation.toggle_priority(params[:priority])
|
|
head :ok
|
|
end
|
|
|
|
def toggle_typing_status
|
|
typing_status_manager = ::Conversations::TypingStatusManager.new(@conversation, current_user, params)
|
|
typing_status_manager.toggle_typing_status
|
|
head :ok
|
|
end
|
|
|
|
def update_last_seen
|
|
update_last_seen_on_conversation(DateTime.now.utc, assignee?)
|
|
end
|
|
|
|
def unread
|
|
last_incoming_message = @conversation.messages.incoming.last
|
|
last_seen_at = last_incoming_message.created_at - 1.second if last_incoming_message.present?
|
|
update_last_seen_on_conversation(last_seen_at, true)
|
|
end
|
|
|
|
def custom_attributes
|
|
@conversation.custom_attributes = params.permit(custom_attributes: {})[:custom_attributes]
|
|
@conversation.save!
|
|
end
|
|
|
|
private
|
|
|
|
def permitted_update_params
|
|
# TODO: Move the other conversation attributes to this method and remove specific endpoints for each attribute
|
|
params.permit(:priority)
|
|
end
|
|
|
|
def attachment_params
|
|
params.permit(:page)
|
|
end
|
|
|
|
def update_last_seen_on_conversation(last_seen_at, update_assignee)
|
|
# rubocop:disable Rails/SkipsModelValidations
|
|
@conversation.update_column(:agent_last_seen_at, last_seen_at)
|
|
@conversation.update_column(:assignee_last_seen_at, last_seen_at) if update_assignee.present?
|
|
# rubocop:enable Rails/SkipsModelValidations
|
|
end
|
|
|
|
def set_conversation_status
|
|
@conversation.status = params[:status]
|
|
@conversation.snoozed_until = parse_date_time(params[:snoozed_until].to_s) if params[:snoozed_until]
|
|
end
|
|
|
|
def assign_conversation
|
|
@conversation.assignee = current_user
|
|
@conversation.save!
|
|
end
|
|
|
|
def conversation
|
|
@conversation ||= Current.account.conversations.find_by!(display_id: params[:id])
|
|
authorize @conversation.inbox, :show?
|
|
end
|
|
|
|
def inbox
|
|
return if params[:inbox_id].blank?
|
|
|
|
@inbox = Current.account.inboxes.find(params[:inbox_id])
|
|
authorize @inbox, :show?
|
|
end
|
|
|
|
def contact
|
|
return if params[:contact_id].blank?
|
|
|
|
@contact = Current.account.contacts.find(params[:contact_id])
|
|
end
|
|
|
|
def contact_inbox
|
|
@contact_inbox = build_contact_inbox
|
|
|
|
# fallback for the old case where we do look up only using source id
|
|
# In future we need to change this and make sure we do look up on combination of inbox_id and source_id
|
|
# and deprecate the support of passing only source_id as the param
|
|
@contact_inbox ||= ::ContactInbox.find_by!(source_id: params[:source_id])
|
|
authorize @contact_inbox.inbox, :show?
|
|
rescue ActiveRecord::RecordNotUnique
|
|
render json: { error: 'source_id should be unique' }, status: :unprocessable_entity
|
|
end
|
|
|
|
def build_contact_inbox
|
|
return if @inbox.blank? || @contact.blank?
|
|
|
|
ContactInboxBuilder.new(
|
|
contact: @contact,
|
|
inbox: @inbox,
|
|
source_id: params[:source_id],
|
|
hmac_verified: hmac_verified?
|
|
).perform
|
|
end
|
|
|
|
def conversation_finder
|
|
@conversation_finder ||= ConversationFinder.new(Current.user, params)
|
|
end
|
|
|
|
def assignee?
|
|
@conversation.assignee_id? && Current.user == @conversation.assignee
|
|
end
|
|
end
|
|
|
|
Api::V1::Accounts::ConversationsController.prepend_mod_with('Api::V1::Accounts::ConversationsController')
|