From 56fbbe92b49bb3b166476347898ba978dab8a267 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Sat, 6 Jan 2024 04:56:52 +0530 Subject: [PATCH] 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 --- .../v1/accounts/conversations_controller.rb | 17 +++++++- .../concerns/access_token_auth_helper.rb | 2 +- app/policies/inbox_policy.rb | 2 +- .../accounts/conversations_controller_spec.rb | 39 +++++++++++++++++++ 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/accounts/conversations_controller.rb b/app/controllers/api/v1/accounts/conversations_controller.rb index a3d3ad645..281ff95de 100644 --- a/app/controllers/api/v1/accounts/conversations_controller.rb +++ b/app/controllers/api/v1/accounts/conversations_controller.rb @@ -60,13 +60,26 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro end 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 @status = @conversation.save! else @status = @conversation.toggle_status 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 def toggle_priority diff --git a/app/controllers/concerns/access_token_auth_helper.rb b/app/controllers/concerns/access_token_auth_helper.rb index 2f4dc4337..c35a28d7d 100644 --- a/app/controllers/concerns/access_token_auth_helper.rb +++ b/app/controllers/concerns/access_token_auth_helper.rb @@ -14,7 +14,7 @@ module AccessTokenAuthHelper render_unauthorized('Invalid Access Token') && return if @access_token.blank? @resource = @access_token.owner - Current.user = @resource if current_user.is_a?(User) + Current.user = @resource if [User, AgentBot].include?(@resource.class) end def validate_bot_access_token! diff --git a/app/policies/inbox_policy.rb b/app/policies/inbox_policy.rb index 891b3414a..0f8fe2307 100644 --- a/app/policies/inbox_policy.rb +++ b/app/policies/inbox_policy.rb @@ -21,7 +21,7 @@ class InboxPolicy < ApplicationPolicy def show? # 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 end diff --git a/spec/controllers/api/v1/accounts/conversations_controller_spec.rb b/spec/controllers/api/v1/accounts/conversations_controller_spec.rb index 90cd018f3..4c4bb9dc9 100644 --- a/spec/controllers/api/v1/accounts/conversations_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/conversations_controller_spec.rb @@ -323,6 +323,9 @@ RSpec.describe 'Conversations API', type: :request do describe 'POST /api/v1/accounts/{account.id}/conversations/:id/toggle_status' do 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 it 'returns unauthorized' do @@ -424,6 +427,42 @@ RSpec.describe 'Conversations API', type: :request do # expect(conversation.reload.status).to eq('pending') # 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 describe 'POST /api/v1/accounts/{account.id}/conversations/:id/toggle_priority' do