Feature: Api to toggle typing status on a conversation (#807)
- api to toggle typing status on a conversation - clients receive webhook events on the same Addresses: #718 , #719 , #775
This commit is contained in:
parent
ba1e0dbda0
commit
dc6398ab56
9 changed files with 119 additions and 3 deletions
|
@ -1,4 +1,5 @@
|
|||
class Api::V1::Accounts::ConversationsController < Api::BaseController
|
||||
include Events::Types
|
||||
before_action :conversation, except: [:index]
|
||||
before_action :contact_inbox, only: [:create]
|
||||
|
||||
|
@ -23,6 +24,16 @@ class Api::V1::Accounts::ConversationsController < Api::BaseController
|
|||
@status = @conversation.toggle_status
|
||||
end
|
||||
|
||||
def toggle_typing_status
|
||||
user = current_user.presence || @resource
|
||||
if params[:typing_status] == 'on'
|
||||
Rails.configuration.dispatcher.dispatch(CONVERSATION_TYPING_ON, Time.zone.now, conversation: @conversation, user: user)
|
||||
elsif params[:typing_status] == 'off'
|
||||
Rails.configuration.dispatcher.dispatch(CONVERSATION_TYPING_OFF, Time.zone.now, conversation: @conversation)
|
||||
end
|
||||
head :ok
|
||||
end
|
||||
|
||||
def update_last_seen
|
||||
@conversation.agent_last_seen_at = parsed_last_seen_at
|
||||
@conversation.save!
|
||||
|
|
|
@ -48,6 +48,28 @@ class ActionCableListener < BaseListener
|
|||
broadcast(user_tokens(account, conversation.inbox.members), CONVERSATION_LOCK_TOGGLE, conversation.lock_event_data)
|
||||
end
|
||||
|
||||
def conversation_typing_on(event)
|
||||
conversation = event.data[:conversation]
|
||||
account = conversation.account
|
||||
user = event.data[:user]
|
||||
tokens = user_tokens(account, conversation.inbox.members) +
|
||||
[conversation.contact.pubsub_token]
|
||||
|
||||
broadcast(tokens, CONVERSATION_TYPING_ON,
|
||||
conversation: conversation.push_event_data, user: user.push_event_data)
|
||||
end
|
||||
|
||||
def conversation_typing_off(event)
|
||||
conversation = event.data[:conversation]
|
||||
account = conversation.account
|
||||
user = event.data[:user]
|
||||
tokens = user_tokens(account, conversation.inbox.members) +
|
||||
[conversation.contact.pubsub_token]
|
||||
|
||||
broadcast(tokens, CONVERSATION_TYPING_OFF,
|
||||
conversation: conversation.push_event_data, user: user.push_event_data)
|
||||
end
|
||||
|
||||
def assignee_changed(event)
|
||||
conversation, account, timestamp = extract_conversation_and_account(event)
|
||||
|
||||
|
|
|
@ -16,4 +16,20 @@ class AgentBot < ApplicationRecord
|
|||
|
||||
has_many :agent_bot_inboxes, dependent: :destroy
|
||||
has_many :inboxes, through: :agent_bot_inboxes
|
||||
|
||||
def push_event_data
|
||||
{
|
||||
name: name,
|
||||
avatar_url: avatar_url,
|
||||
type: 'agent_bot'
|
||||
}
|
||||
end
|
||||
|
||||
def webhook_data
|
||||
{
|
||||
id: id,
|
||||
name: name,
|
||||
type: 'agent_bot'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -50,6 +50,7 @@ class Contact < ApplicationRecord
|
|||
id: id,
|
||||
name: name,
|
||||
thumbnail: avatar_url,
|
||||
type: 'contact',
|
||||
pubsub_token: pubsub_token
|
||||
}
|
||||
end
|
||||
|
@ -58,7 +59,8 @@ class Contact < ApplicationRecord
|
|||
{
|
||||
id: id,
|
||||
name: name,
|
||||
avatar: avatar_url
|
||||
avatar: avatar_url,
|
||||
type: 'contact'
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -129,7 +129,8 @@ class User < ApplicationRecord
|
|||
def push_event_data
|
||||
{
|
||||
name: name,
|
||||
avatar_url: avatar_url
|
||||
avatar_url: avatar_url,
|
||||
type: 'user'
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -137,7 +138,8 @@ class User < ApplicationRecord
|
|||
{
|
||||
id: id,
|
||||
name: name,
|
||||
email: email
|
||||
email: email,
|
||||
type: 'user'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -49,6 +49,7 @@ Rails.application.routes.draw do
|
|||
end
|
||||
member do
|
||||
post :toggle_status
|
||||
post :toggle_typing_status
|
||||
post :update_last_seen
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,6 +15,8 @@ module Events::Types
|
|||
CONVERSATION_RESOLVED = 'conversation.resolved'
|
||||
CONVERSATION_LOCK_TOGGLE = 'conversation.lock_toggle'
|
||||
ASSIGNEE_CHANGED = 'assignee.changed'
|
||||
CONVERSATION_TYPING_ON = 'conversation.typing_on'
|
||||
CONVERSATION_TYPING_OFF = 'conversation.typing_off'
|
||||
|
||||
# message events
|
||||
MESSAGE_CREATED = 'message.created'
|
||||
|
|
|
@ -122,6 +122,34 @@ RSpec.describe 'Conversations API', type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/accounts/{account.id}/conversations/:id/toggle_typing_status' do
|
||||
let(:conversation) { create(:conversation, account: account) }
|
||||
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/toggle_typing_status"
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
it 'toggles the conversation status' do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/toggle_typing_status",
|
||||
headers: agent.create_new_auth_token,
|
||||
params: { typing_status: 'on' },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||
.with(Conversation::CONVERSATION_TYPING_ON, kind_of(Time), { conversation: conversation, user: agent })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/accounts/{account.id}/conversations/:id/update_last_seen' do
|
||||
let(:conversation) { create(:conversation, account: account) }
|
||||
|
||||
|
|
|
@ -29,4 +29,36 @@ describe ActionCableListener do
|
|||
listener.message_created(event)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#typing_on' do
|
||||
let(:event_name) { :'conversation.typing_on' }
|
||||
let!(:event) { Events::Base.new(event_name, Time.zone.now, conversation: conversation, user: agent) }
|
||||
|
||||
it 'sends message to account admins, inbox agents and the contact' do
|
||||
# HACK: to reload conversation inbox members
|
||||
expect(conversation.inbox.reload.inbox_members.count).to eq(1)
|
||||
expect(ActionCableBroadcastJob).to receive(:perform_later).with(
|
||||
[agent.pubsub_token, admin.pubsub_token, conversation.contact.pubsub_token],
|
||||
'conversation.typing_on', conversation: conversation.push_event_data,
|
||||
user: agent.push_event_data
|
||||
)
|
||||
listener.conversation_typing_on(event)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#typing_off' do
|
||||
let(:event_name) { :'conversation.typing_off' }
|
||||
let!(:event) { Events::Base.new(event_name, Time.zone.now, conversation: conversation, user: agent) }
|
||||
|
||||
it 'sends message to account admins, inbox agents and the contact' do
|
||||
# HACK: to reload conversation inbox members
|
||||
expect(conversation.inbox.reload.inbox_members.count).to eq(1)
|
||||
expect(ActionCableBroadcastJob).to receive(:perform_later).with(
|
||||
[agent.pubsub_token, admin.pubsub_token, conversation.contact.pubsub_token],
|
||||
'conversation.typing_off', conversation: conversation.push_event_data,
|
||||
user: agent.push_event_data
|
||||
)
|
||||
listener.conversation_typing_off(event)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue