feat: trigger handoff when agent bot is the actor (#8639)
- This PR adds a feature to auto-trigger handoff events when an Agent bot toggles a conversation status from Pending to Open Co-authored-by: Sojan <sojan@pepalo.com>
This commit is contained in:
@@ -60,13 +60,26 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
|||||||
end
|
end
|
||||||
|
|
||||||
def toggle_status
|
def toggle_status
|
||||||
if params[:status].present?
|
# FIXME: move this logic into a service object
|
||||||
|
if pending_to_open_by_bot?
|
||||||
|
@conversation.bot_handoff!
|
||||||
|
elsif params[:status].present?
|
||||||
set_conversation_status
|
set_conversation_status
|
||||||
@status = @conversation.save!
|
@status = @conversation.save!
|
||||||
else
|
else
|
||||||
@status = @conversation.toggle_status
|
@status = @conversation.toggle_status
|
||||||
end
|
end
|
||||||
assign_conversation if @conversation.status == 'open' && Current.user.is_a?(User) && Current.user&.agent?
|
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
|
end
|
||||||
|
|
||||||
def toggle_priority
|
def toggle_priority
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ module AccessTokenAuthHelper
|
|||||||
render_unauthorized('Invalid Access Token') && return if @access_token.blank?
|
render_unauthorized('Invalid Access Token') && return if @access_token.blank?
|
||||||
|
|
||||||
@resource = @access_token.owner
|
@resource = @access_token.owner
|
||||||
Current.user = @resource if current_user.is_a?(User)
|
Current.user = @resource if [User, AgentBot].include?(@resource.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_bot_access_token!
|
def validate_bot_access_token!
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class InboxPolicy < ApplicationPolicy
|
|||||||
|
|
||||||
def show?
|
def show?
|
||||||
# FIXME: for agent bots, lets bring this validation to policies as well in future
|
# FIXME: for agent bots, lets bring this validation to policies as well in future
|
||||||
return true if @user.blank?
|
return true if @user.is_a?(AgentBot)
|
||||||
|
|
||||||
Current.user.assigned_inboxes.include? record
|
Current.user.assigned_inboxes.include? record
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -323,6 +323,9 @@ RSpec.describe 'Conversations API', type: :request do
|
|||||||
|
|
||||||
describe 'POST /api/v1/accounts/{account.id}/conversations/:id/toggle_status' do
|
describe 'POST /api/v1/accounts/{account.id}/conversations/:id/toggle_status' do
|
||||||
let(:conversation) { create(:conversation, account: account) }
|
let(:conversation) { create(:conversation, account: account) }
|
||||||
|
let(:inbox) { create(:inbox, account: account) }
|
||||||
|
let(:pending_conversation) { create(:conversation, inbox: inbox, account: account, status: 'pending') }
|
||||||
|
let(:agent_bot) { create(:agent_bot, account: account) }
|
||||||
|
|
||||||
context 'when it is an unauthenticated user' do
|
context 'when it is an unauthenticated user' do
|
||||||
it 'returns unauthorized' do
|
it 'returns unauthorized' do
|
||||||
@@ -424,6 +427,42 @@ RSpec.describe 'Conversations API', type: :request do
|
|||||||
# expect(conversation.reload.status).to eq('pending')
|
# expect(conversation.reload.status).to eq('pending')
|
||||||
# end
|
# end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated bot' do
|
||||||
|
# this test will basically ensure that the status actually changes
|
||||||
|
# regardless of the value to be done
|
||||||
|
it 'returns authorized for arbritrary status' do
|
||||||
|
create(:agent_bot_inbox, inbox: inbox, agent_bot: agent_bot)
|
||||||
|
|
||||||
|
conversation.update!(status: 'open')
|
||||||
|
expect(conversation.reload.status).to eq('open')
|
||||||
|
snoozed_until = (DateTime.now.utc + 2.days).to_i
|
||||||
|
|
||||||
|
post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/toggle_status",
|
||||||
|
headers: { api_access_token: agent_bot.access_token.token },
|
||||||
|
params: { status: 'snoozed', snoozed_until: snoozed_until },
|
||||||
|
as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(conversation.reload.status).to eq('snoozed')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'triggers handoff event when moving from pending to open' do
|
||||||
|
create(:agent_bot_inbox, inbox: inbox, agent_bot: agent_bot)
|
||||||
|
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||||
|
|
||||||
|
post "/api/v1/accounts/#{account.id}/conversations/#{pending_conversation.display_id}/toggle_status",
|
||||||
|
headers: { api_access_token: agent_bot.access_token.token },
|
||||||
|
params: { status: 'open' },
|
||||||
|
as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(pending_conversation.reload.status).to eq('open')
|
||||||
|
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||||
|
.with(Events::Types::CONVERSATION_BOT_HANDOFF, kind_of(Time), conversation: pending_conversation, notifiable_assignee_change: false,
|
||||||
|
changed_attributes: anything, performed_by: anything)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'POST /api/v1/accounts/{account.id}/conversations/:id/toggle_priority' do
|
describe 'POST /api/v1/accounts/{account.id}/conversations/:id/toggle_priority' do
|
||||||
|
|||||||
Reference in New Issue
Block a user