Chore: Minor bugfixes and housekeeping tasks (#896)
This commit is contained in:
parent
93d8a25877
commit
dafabac796
21 changed files with 271 additions and 51 deletions
|
@ -1,7 +1,7 @@
|
||||||
.search {
|
.search {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: 2rem;
|
margin-right: 2rem;
|
||||||
max-width: 24rem;
|
max-width: 44rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,13 @@ class Api::V1::Accounts::ConversationsController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def toggle_status
|
def toggle_status
|
||||||
|
if params[:status]
|
||||||
|
@conversation.status = params[:status]
|
||||||
|
@status = @conversation.save
|
||||||
|
else
|
||||||
@status = @conversation.toggle_status
|
@status = @conversation.toggle_status
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def toggle_typing_status
|
def toggle_typing_status
|
||||||
if params[:typing_status] == 'on'
|
if params[:typing_status] == 'on'
|
||||||
|
|
|
@ -6,18 +6,8 @@ class SuperAdmin::AccountUsersController < SuperAdmin::ApplicationController
|
||||||
resource = resource_class.new(resource_params)
|
resource = resource_class.new(resource_params)
|
||||||
authorize_resource(resource)
|
authorize_resource(resource)
|
||||||
|
|
||||||
redirect_resource = params[:redirect_to] == 'user' ? resource.user : resource.account
|
notice = resource.save ? translate_with_resource('create.success') : resource.errors.full_messages.first
|
||||||
if resource.save
|
redirect_back(fallback_location: [namespace, resource.account], notice: notice)
|
||||||
redirect_to(
|
|
||||||
[namespace, redirect_resource],
|
|
||||||
notice: translate_with_resource('create.success')
|
|
||||||
)
|
|
||||||
else
|
|
||||||
redirect_to(
|
|
||||||
[namespace, redirect_resource],
|
|
||||||
notice: resource.errors.full_messages.first
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
|
@ -26,7 +16,7 @@ class SuperAdmin::AccountUsersController < SuperAdmin::ApplicationController
|
||||||
else
|
else
|
||||||
flash[:error] = requested_resource.errors.full_messages.join('<br/>')
|
flash[:error] = requested_resource.errors.full_messages.join('<br/>')
|
||||||
end
|
end
|
||||||
redirect_to([namespace, requested_resource.account])
|
redirect_back(fallback_location: [namespace, requested_resource.account])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Override this method to specify custom lookup behavior.
|
# Override this method to specify custom lookup behavior.
|
||||||
|
|
44
app/controllers/super_admin/agent_bots_controller.rb
Normal file
44
app/controllers/super_admin/agent_bots_controller.rb
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
class SuperAdmin::AgentBotsController < SuperAdmin::ApplicationController
|
||||||
|
# Overwrite any of the RESTful controller actions to implement custom behavior
|
||||||
|
# For example, you may want to send an email after a foo is updated.
|
||||||
|
#
|
||||||
|
# def update
|
||||||
|
# super
|
||||||
|
# send_foo_updated_email(requested_resource)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Override this method to specify custom lookup behavior.
|
||||||
|
# This will be used to set the resource for the `show`, `edit`, and `update`
|
||||||
|
# actions.
|
||||||
|
#
|
||||||
|
# def find_resource(param)
|
||||||
|
# Foo.find_by!(slug: param)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# The result of this lookup will be available as `requested_resource`
|
||||||
|
|
||||||
|
# Override this if you have certain roles that require a subset
|
||||||
|
# this will be used to set the records shown on the `index` action.
|
||||||
|
#
|
||||||
|
# def scoped_resource
|
||||||
|
# if current_user.super_admin?
|
||||||
|
# resource_class
|
||||||
|
# else
|
||||||
|
# resource_class.with_less_stuff
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Override `resource_params` if you want to transform the submitted
|
||||||
|
# data before it's persisted. For example, the following would turn all
|
||||||
|
# empty values into nil values. It uses other APIs such as `resource_class`
|
||||||
|
# and `dashboard`:
|
||||||
|
#
|
||||||
|
# def resource_params
|
||||||
|
# params.require(resource_class.model_name.param_key).
|
||||||
|
# permit(dashboard.permitted_attributes).
|
||||||
|
# transform_values { |value| value == "" ? nil : value }
|
||||||
|
# end
|
||||||
|
|
||||||
|
# See https://administrate-prototype.herokuapp.com/customizing_controller_actions
|
||||||
|
# for more information
|
||||||
|
end
|
|
@ -55,7 +55,11 @@ class AccessTokenDashboard < Administrate::BaseDashboard
|
||||||
# COLLECTION_FILTERS = {
|
# COLLECTION_FILTERS = {
|
||||||
# open: ->(resources) { resources.where(open: true) }
|
# open: ->(resources) { resources.where(open: true) }
|
||||||
# }.freeze
|
# }.freeze
|
||||||
COLLECTION_FILTERS = {}.freeze
|
COLLECTION_FILTERS = {
|
||||||
|
user: ->(resources) { resources.where(owner_type: 'User') },
|
||||||
|
super_admin: ->(resources) { resources.where(owner_type: 'SuperAdmin') },
|
||||||
|
agent_bot: ->(resources) { resources.where(owner_type: 'AgentBot') }
|
||||||
|
}.freeze
|
||||||
|
|
||||||
# Overwrite this method to customize how access tokens are displayed
|
# Overwrite this method to customize how access tokens are displayed
|
||||||
# across all pages of the admin dashboard.
|
# across all pages of the admin dashboard.
|
||||||
|
|
73
app/dashboards/agent_bot_dashboard.rb
Normal file
73
app/dashboards/agent_bot_dashboard.rb
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
require 'administrate/base_dashboard'
|
||||||
|
|
||||||
|
class AgentBotDashboard < Administrate::BaseDashboard
|
||||||
|
# ATTRIBUTE_TYPES
|
||||||
|
# a hash that describes the type of each of the model's fields.
|
||||||
|
#
|
||||||
|
# Each different type represents an Administrate::Field object,
|
||||||
|
# which determines how the attribute is displayed
|
||||||
|
# on pages throughout the dashboard.
|
||||||
|
ATTRIBUTE_TYPES = {
|
||||||
|
access_token: Field::HasOne,
|
||||||
|
avatar_url: AvatarField,
|
||||||
|
id: Field::Number,
|
||||||
|
name: Field::String,
|
||||||
|
description: Field::String,
|
||||||
|
outgoing_url: Field::String,
|
||||||
|
created_at: Field::DateTime,
|
||||||
|
updated_at: Field::DateTime,
|
||||||
|
hide_input_for_bot_conversations: Field::Boolean
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
# COLLECTION_ATTRIBUTES
|
||||||
|
# an array of attributes that will be displayed on the model's index page.
|
||||||
|
#
|
||||||
|
# By default, it's limited to four items to reduce clutter on index pages.
|
||||||
|
# Feel free to add, remove, or rearrange items.
|
||||||
|
COLLECTION_ATTRIBUTES = %i[
|
||||||
|
id
|
||||||
|
avatar_url
|
||||||
|
name
|
||||||
|
outgoing_url
|
||||||
|
].freeze
|
||||||
|
|
||||||
|
# SHOW_PAGE_ATTRIBUTES
|
||||||
|
# an array of attributes that will be displayed on the model's show page.
|
||||||
|
SHOW_PAGE_ATTRIBUTES = %i[
|
||||||
|
id
|
||||||
|
avatar_url
|
||||||
|
name
|
||||||
|
description
|
||||||
|
outgoing_url
|
||||||
|
hide_input_for_bot_conversations
|
||||||
|
].freeze
|
||||||
|
|
||||||
|
# FORM_ATTRIBUTES
|
||||||
|
# an array of attributes that will be displayed
|
||||||
|
# on the model's form (`new` and `edit`) pages.
|
||||||
|
FORM_ATTRIBUTES = %i[
|
||||||
|
name
|
||||||
|
description
|
||||||
|
outgoing_url
|
||||||
|
hide_input_for_bot_conversations
|
||||||
|
].freeze
|
||||||
|
|
||||||
|
# COLLECTION_FILTERS
|
||||||
|
# a hash that defines filters that can be used while searching via the search
|
||||||
|
# field of the dashboard.
|
||||||
|
#
|
||||||
|
# For example to add an option to search for open resources by typing "open:"
|
||||||
|
# in the search field:
|
||||||
|
#
|
||||||
|
# COLLECTION_FILTERS = {
|
||||||
|
# open: ->(resources) { resources.where(open: true) }
|
||||||
|
# }.freeze
|
||||||
|
COLLECTION_FILTERS = {}.freeze
|
||||||
|
|
||||||
|
# Overwrite this method to customize how agent bots are displayed
|
||||||
|
# across all pages of the admin dashboard.
|
||||||
|
#
|
||||||
|
# def display_resource(agent_bot)
|
||||||
|
# "AgentBot ##{agent_bot.id}"
|
||||||
|
# end
|
||||||
|
end
|
|
@ -50,13 +50,11 @@ class Conversation < ApplicationRecord
|
||||||
has_many :messages, dependent: :destroy, autosave: true
|
has_many :messages, dependent: :destroy, autosave: true
|
||||||
|
|
||||||
before_create :set_display_id, unless: :display_id?
|
before_create :set_display_id, unless: :display_id?
|
||||||
|
|
||||||
before_create :set_bot_conversation
|
before_create :set_bot_conversation
|
||||||
|
after_create :notify_conversation_creation
|
||||||
|
after_save :run_round_robin
|
||||||
after_update :notify_status_change, :create_activity
|
after_update :notify_status_change, :create_activity
|
||||||
|
|
||||||
after_create :notify_conversation_creation, :run_round_robin
|
|
||||||
|
|
||||||
acts_as_taggable_on :labels
|
acts_as_taggable_on :labels
|
||||||
|
|
||||||
def update_assignee(agent = nil)
|
def update_assignee(agent = nil)
|
||||||
|
@ -173,10 +171,24 @@ class Conversation < ApplicationRecord
|
||||||
Rails.configuration.dispatcher.dispatch(event_name, Time.zone.now, conversation: self)
|
Rails.configuration.dispatcher.dispatch(event_name, Time.zone.now, conversation: self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def should_round_robin?
|
||||||
|
return false unless inbox.enable_auto_assignment?
|
||||||
|
|
||||||
|
# run only if assignee is blank or doesn't have access to inbox
|
||||||
|
assignee.blank? || inbox.members.exclude?(assignee)
|
||||||
|
end
|
||||||
|
|
||||||
|
def conversation_status_changed_to_open?
|
||||||
|
return false unless open?
|
||||||
|
# saved_change_to_status? method only works in case of update
|
||||||
|
return true if previous_changes.key?(:id) || saved_change_to_status?
|
||||||
|
end
|
||||||
|
|
||||||
def run_round_robin
|
def run_round_robin
|
||||||
return unless inbox.enable_auto_assignment
|
# Round robin kicks in on conversation create & update
|
||||||
return if assignee
|
# run it only when conversation status changes to open
|
||||||
return if bot?
|
return unless conversation_status_changed_to_open?
|
||||||
|
return unless should_round_robin?
|
||||||
|
|
||||||
inbox.next_available_agent.then { |new_assignee| update_assignee(new_assignee) }
|
inbox.next_available_agent.then { |new_assignee| update_assignee(new_assignee) }
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,8 +18,11 @@ class MessageTemplates::Template::EmailCollect
|
||||||
delegate :inbox, to: :message
|
delegate :inbox, to: :message
|
||||||
|
|
||||||
def typical_reply_message_params
|
def typical_reply_message_params
|
||||||
|
content = @conversation.inbox&.channel&.agent_away_message
|
||||||
|
if content.blank?
|
||||||
content = I18n.t('conversations.templates.typical_reply_message_body',
|
content = I18n.t('conversations.templates.typical_reply_message_body',
|
||||||
account_name: account.name)
|
account_name: account.name)
|
||||||
|
end
|
||||||
|
|
||||||
{
|
{
|
||||||
account_id: @conversation.account_id,
|
account_id: @conversation.account_id,
|
||||||
|
|
|
@ -4,10 +4,10 @@ json.uid resource.uid
|
||||||
json.name resource.name
|
json.name resource.name
|
||||||
json.nickname resource.nickname
|
json.nickname resource.nickname
|
||||||
json.email resource.email
|
json.email resource.email
|
||||||
json.account_id resource.active_account_user.account_id
|
json.account_id resource.active_account_user&.account_id
|
||||||
json.pubsub_token resource.pubsub_token
|
json.pubsub_token resource.pubsub_token
|
||||||
json.role resource.active_account_user.role
|
json.role resource.active_account_user&.role
|
||||||
json.inviter_id resource.active_account_user.inviter_id
|
json.inviter_id resource.active_account_user&.inviter_id
|
||||||
json.confirmed resource.confirmed?
|
json.confirmed resource.confirmed?
|
||||||
json.avatar_url resource.avatar_url
|
json.avatar_url resource.avatar_url
|
||||||
json.access_token resource.access_token.token
|
json.access_token resource.access_token.token
|
||||||
|
|
|
@ -72,7 +72,6 @@ as well as a link to its edit page.
|
||||||
<% account_user_page.attributes.each do |attribute| -%>
|
<% account_user_page.attributes.each do |attribute| -%>
|
||||||
<% if attribute.name == "account" %>
|
<% if attribute.name == "account" %>
|
||||||
<%= f.hidden_field('account_id', value: page.resource.id) %>
|
<%= f.hidden_field('account_id', value: page.resource.id) %>
|
||||||
<%= f.hidden_field('redirect_to', value: 'user') %>
|
|
||||||
<% else %>
|
<% else %>
|
||||||
<div class="field-unit field-unit--<%= attribute.html_class %> field-unit--<%= requireness(attribute) %>">
|
<div class="field-unit field-unit--<%= attribute.html_class %> field-unit--<%= requireness(attribute) %>">
|
||||||
<%= render_field attribute, f: f %>
|
<%= render_field attribute, f: f %>
|
||||||
|
|
|
@ -30,7 +30,7 @@ as defined by the routes in the `admin/` namespace
|
||||||
<%= link_to "Dashboard", super_admin_root_url %>
|
<%= link_to "Dashboard", super_admin_root_url %>
|
||||||
</li>
|
</li>
|
||||||
<% Administrate::Namespace.new(namespace).resources.each do |resource| %>
|
<% Administrate::Namespace.new(namespace).resources.each do |resource| %>
|
||||||
<% next if ["account_users", "dashboard", "devise/sessions"].include? resource.resource %>
|
<% next if ["account_users", "agent_bots","dashboard", "devise/sessions"].include? resource.resource %>
|
||||||
<li class="navigation__link navigation__link--<%= nav_link_state(resource) %>">
|
<li class="navigation__link navigation__link--<%= nav_link_state(resource) %>">
|
||||||
<i class="<%= sidebar_icons[resource.resource.to_sym] %>"></i>
|
<i class="<%= sidebar_icons[resource.resource.to_sym] %>"></i>
|
||||||
<%= link_to(
|
<%= link_to(
|
||||||
|
|
|
@ -72,7 +72,6 @@ as well as a link to its edit page.
|
||||||
<% account_user_page.attributes.each do |attribute| -%>
|
<% account_user_page.attributes.each do |attribute| -%>
|
||||||
<% if attribute.name == "user" %>
|
<% if attribute.name == "user" %>
|
||||||
<%= f.hidden_field('user_id', value: page.resource.id) %>
|
<%= f.hidden_field('user_id', value: page.resource.id) %>
|
||||||
<%= f.hidden_field('redirect_to', value: 'user') %>
|
|
||||||
<% else %>
|
<% else %>
|
||||||
<div class="field-unit field-unit--<%= attribute.html_class %> field-unit--<%= requireness(attribute) %>">
|
<div class="field-unit field-unit--<%= attribute.html_class %> field-unit--<%= requireness(attribute) %>">
|
||||||
<%= render_field attribute, f: f %>
|
<%= render_field attribute, f: f %>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
window.chatwootSettings = {
|
window.chatwootSettings = {
|
||||||
hideMessageBubble: false,
|
hideMessageBubble: false,
|
||||||
position: 'left',
|
position: 'left',
|
||||||
locale: 'fr',
|
locale: 'en',
|
||||||
};
|
};
|
||||||
|
|
||||||
(function(d,t) {
|
(function(d,t) {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
# DO NOT change the order of features EVER
|
# DO NOT change the order of features EVER
|
||||||
- name: inbound_emails
|
- name: inbound_emails
|
||||||
enabled: false
|
enabled: false
|
||||||
- name: test
|
- name: channel_email
|
||||||
enabled: false
|
enabled: false
|
||||||
|
- name: channel_facebook
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
|
|
@ -176,13 +176,17 @@ Rails.application.routes.draw do
|
||||||
devise_scope :super_admin do
|
devise_scope :super_admin do
|
||||||
get 'super_admin/logout', to: 'super_admin/devise/sessions#destroy'
|
get 'super_admin/logout', to: 'super_admin/devise/sessions#destroy'
|
||||||
namespace :super_admin do
|
namespace :super_admin do
|
||||||
|
root to: 'dashboard#index'
|
||||||
|
|
||||||
|
# order of resources affect the order of sidebar navigation in super admin
|
||||||
resources :accounts
|
resources :accounts
|
||||||
resources :account_users, only: [:new, :create, :destroy]
|
resources :users, only: [:index, :new, :create, :show, :edit, :update]
|
||||||
resources :users
|
|
||||||
resources :super_admins
|
resources :super_admins
|
||||||
resources :access_tokens, only: [:index, :show]
|
resources :access_tokens, only: [:index, :show]
|
||||||
|
|
||||||
root to: 'dashboard#index'
|
# resources that doesn't appear in primary navigation in super admin
|
||||||
|
resources :account_users, only: [:new, :create, :destroy]
|
||||||
|
resources :agent_bots, only: [:index, :new, :create, :show, :edit, :update]
|
||||||
end
|
end
|
||||||
authenticated :super_admin do
|
authenticated :super_admin do
|
||||||
mount Sidekiq::Web => '/monitoring/sidekiq'
|
mount Sidekiq::Web => '/monitoring/sidekiq'
|
||||||
|
|
|
@ -119,6 +119,18 @@ RSpec.describe 'Conversations API', type: :request do
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
expect(conversation.reload.status).to eq('open')
|
expect(conversation.reload.status).to eq('open')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'toggles the conversation status to specific status when parameter is passed' do
|
||||||
|
expect(conversation.status).to eq('open')
|
||||||
|
|
||||||
|
post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/toggle_status",
|
||||||
|
headers: agent.create_new_auth_token,
|
||||||
|
params: { status: 'bot' },
|
||||||
|
as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(conversation.reload.status).to eq('bot')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
25
spec/controllers/super_admin/agent_bots_controller_spec.rb
Normal file
25
spec/controllers/super_admin/agent_bots_controller_spec.rb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Super Admin agent-bots API', type: :request do
|
||||||
|
let(:super_admin) { create(:super_admin) }
|
||||||
|
|
||||||
|
describe 'GET /super_admin/agent_bots' do
|
||||||
|
context 'when it is an unauthenticated super admin' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get '/super_admin/agent_bots'
|
||||||
|
expect(response).to have_http_status(:redirect)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated super admin' do
|
||||||
|
let!(:agent_bot) { create(:agent_bot) }
|
||||||
|
|
||||||
|
it 'shows the list of users' do
|
||||||
|
sign_in super_admin
|
||||||
|
get '/super_admin/agent_bots'
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(response.body).to include(agent_bot.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,6 +15,7 @@ describe ::MessageFinder do
|
||||||
create(:message, account: account, inbox: inbox, conversation: conversation)
|
create(:message, account: account, inbox: inbox, conversation: conversation)
|
||||||
create(:message, message_type: 'activity', account: account, inbox: inbox, conversation: conversation)
|
create(:message, message_type: 'activity', account: account, inbox: inbox, conversation: conversation)
|
||||||
create(:message, message_type: 'activity', account: account, inbox: inbox, conversation: conversation)
|
create(:message, message_type: 'activity', account: account, inbox: inbox, conversation: conversation)
|
||||||
|
# this outgoing message creates 3 additional messages because of the hook execution service
|
||||||
create(:message, message_type: 'outgoing', account: account, inbox: inbox, conversation: conversation)
|
create(:message, message_type: 'outgoing', account: account, inbox: inbox, conversation: conversation)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@ require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe ConversationReplyMailer, type: :mailer do
|
RSpec.describe ConversationReplyMailer, type: :mailer do
|
||||||
describe 'reply_with_summary' do
|
describe 'reply_with_summary' do
|
||||||
let(:agent) { create(:user, email: 'agent1@example.com') }
|
let!(:account) { create(:account) }
|
||||||
|
let!(:agent) { create(:user, email: 'agent1@example.com', account: account) }
|
||||||
let(:class_instance) { described_class.new }
|
let(:class_instance) { described_class.new }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -33,8 +34,10 @@ RSpec.describe ConversationReplyMailer, type: :mailer do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when custom domain and email is not enabled' do
|
context 'when custom domain and email is not enabled' do
|
||||||
let(:conversation) { create(:conversation, assignee: agent) }
|
let(:inbox) { create(:inbox, account: account) }
|
||||||
let(:message) { create(:message, conversation: conversation) }
|
let(:inbox_member) { create(:inbox_member, user: agent, inbox: inbox) }
|
||||||
|
let(:conversation) { create(:conversation, assignee: agent, inbox: inbox_member.inbox, account: account) }
|
||||||
|
let!(:message) { create(:message, conversation: conversation, account: account) }
|
||||||
let(:mail) { described_class.reply_with_summary(message.conversation, Time.zone.now).deliver_now }
|
let(:mail) { described_class.reply_with_summary(message.conversation, Time.zone.now).deliver_now }
|
||||||
|
|
||||||
it 'renders the receiver email' do
|
it 'renders the receiver email' do
|
||||||
|
|
|
@ -21,6 +21,31 @@ RSpec.describe Conversation, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.after_create' do
|
||||||
|
let(:account) { create(:account) }
|
||||||
|
let(:agent) { create(:user, email: 'agent1@example.com', account: account) }
|
||||||
|
let(:inbox) { create(:inbox, account: account) }
|
||||||
|
let(:conversation) do
|
||||||
|
create(
|
||||||
|
:conversation,
|
||||||
|
account: account,
|
||||||
|
contact: create(:contact, account: account),
|
||||||
|
inbox: inbox,
|
||||||
|
assignee: nil
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'runs after_create callbacks' do
|
||||||
|
# send_events
|
||||||
|
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||||
|
.with(described_class::CONVERSATION_CREATED, kind_of(Time), conversation: conversation)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '.after_update' do
|
describe '.after_update' do
|
||||||
let(:account) { create(:account) }
|
let(:account) { create(:account) }
|
||||||
let(:conversation) do
|
let(:conversation) do
|
||||||
|
@ -68,7 +93,7 @@ RSpec.describe Conversation, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.after_create' do
|
describe '#round robin' do
|
||||||
let(:account) { create(:account) }
|
let(:account) { create(:account) }
|
||||||
let(:agent) { create(:user, email: 'agent1@example.com', account: account) }
|
let(:agent) { create(:user, email: 'agent1@example.com', account: account) }
|
||||||
let(:inbox) { create(:inbox, account: account) }
|
let(:inbox) { create(:inbox, account: account) }
|
||||||
|
@ -83,15 +108,10 @@ RSpec.describe Conversation, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
|
||||||
allow(Redis::Alfred).to receive(:rpoplpush).and_return(agent.id)
|
allow(Redis::Alfred).to receive(:rpoplpush).and_return(agent.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'runs after_create callbacks' do
|
it 'runs round robin on after_save callbacks' do
|
||||||
# send_events
|
|
||||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
|
||||||
.with(described_class::CONVERSATION_CREATED, kind_of(Time), conversation: conversation)
|
|
||||||
|
|
||||||
# run_round_robin
|
# run_round_robin
|
||||||
expect(conversation.reload.assignee).to eq(agent)
|
expect(conversation.reload.assignee).to eq(agent)
|
||||||
end
|
end
|
||||||
|
@ -99,13 +119,36 @@ RSpec.describe Conversation, type: :model do
|
||||||
it 'will not auto assign agent if enable_auto_assignment is false' do
|
it 'will not auto assign agent if enable_auto_assignment is false' do
|
||||||
inbox.update(enable_auto_assignment: false)
|
inbox.update(enable_auto_assignment: false)
|
||||||
|
|
||||||
# send_events
|
# run_round_robin
|
||||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
expect(conversation.reload.assignee).to eq(nil)
|
||||||
.with(described_class::CONVERSATION_CREATED, kind_of(Time), conversation: conversation)
|
end
|
||||||
|
|
||||||
|
it 'will not auto assign agent if its a bot conversation' do
|
||||||
|
conversation = create(
|
||||||
|
:conversation,
|
||||||
|
account: account,
|
||||||
|
contact: create(:contact, account: account),
|
||||||
|
inbox: inbox,
|
||||||
|
status: 'bot',
|
||||||
|
assignee: nil
|
||||||
|
)
|
||||||
|
|
||||||
# run_round_robin
|
# run_round_robin
|
||||||
expect(conversation.reload.assignee).to eq(nil)
|
expect(conversation.reload.assignee).to eq(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'gets triggered on update only when status changes to open' do
|
||||||
|
conversation.status = 'resolved'
|
||||||
|
conversation.save!
|
||||||
|
expect(conversation.reload.assignee).to eq(agent)
|
||||||
|
|
||||||
|
# round robin changes assignee in this case since agent doesn't have access to inbox
|
||||||
|
agent2 = create(:user, email: 'agent2@example.com', account: account)
|
||||||
|
allow(Redis::Alfred).to receive(:rpoplpush).and_return(agent2.id)
|
||||||
|
conversation.status = 'open'
|
||||||
|
conversation.save!
|
||||||
|
expect(conversation.reload.assignee).to eq(agent2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#update_assignee' do
|
describe '#update_assignee' do
|
||||||
|
|
|
@ -18,7 +18,7 @@ post:
|
||||||
properties:
|
properties:
|
||||||
status:
|
status:
|
||||||
type: string
|
type: string
|
||||||
enum: ["open", "resolved"]
|
enum: ["open", "resolved", "bot"]
|
||||||
required: true
|
required: true
|
||||||
description: The status of the conversation
|
description: The status of the conversation
|
||||||
responses:
|
responses:
|
||||||
|
|
Loading…
Reference in a new issue