chore: Move agent availability to Account level (#3074)
- Move agent availability to the account level
This commit is contained in:
parent
1c6a539c0a
commit
c54aae21ff
84 changed files with 618 additions and 148 deletions
|
@ -9,21 +9,18 @@ class Api::V1::Accounts::AgentsController < Api::V1::Accounts::BaseController
|
|||
@agents = agents
|
||||
end
|
||||
|
||||
def create; end
|
||||
|
||||
def update
|
||||
@agent.update!(agent_params.slice(:name).compact)
|
||||
@agent.current_account_user.update!(agent_params.slice(:role, :availability, :auto_offline).compact)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@agent.current_account_user.destroy
|
||||
head :ok
|
||||
end
|
||||
|
||||
def update
|
||||
@agent.update!(agent_params.except(:role))
|
||||
@agent.current_account_user.update!(role: agent_params[:role]) if agent_params[:role]
|
||||
render partial: 'api/v1/models/agent.json.jbuilder', locals: { resource: @agent }
|
||||
end
|
||||
|
||||
def create
|
||||
render partial: 'api/v1/models/agent.json.jbuilder', locals: { resource: @user }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_authorization
|
||||
|
@ -47,22 +44,25 @@ class Api::V1::Accounts::AgentsController < Api::V1::Accounts::BaseController
|
|||
end
|
||||
|
||||
def save_account_user
|
||||
AccountUser.create!(
|
||||
AccountUser.create!({
|
||||
account_id: Current.account.id,
|
||||
user_id: @user.id,
|
||||
role: new_agent_params[:role],
|
||||
inviter_id: current_user.id
|
||||
)
|
||||
}.merge({
|
||||
role: new_agent_params[:role],
|
||||
availability: new_agent_params[:availability],
|
||||
auto_offline: new_agent_params[:auto_offline]
|
||||
}.compact))
|
||||
end
|
||||
|
||||
def agent_params
|
||||
params.require(:agent).permit(:email, :name, :role)
|
||||
params.require(:agent).permit(:name, :email, :name, :role, :availability, :auto_offline)
|
||||
end
|
||||
|
||||
def new_agent_params
|
||||
# intial string ensures the password requirements are met
|
||||
temp_password = "1!aA#{SecureRandom.alphanumeric(12)}"
|
||||
params.require(:agent).permit(:email, :name, :role)
|
||||
params.require(:agent).permit(:email, :name, :role, :availability, :auto_offline)
|
||||
.merge!(password: temp_password, password_confirmation: temp_password, inviter: current_user)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
class Api::V1::ProfilesController < Api::BaseController
|
||||
before_action :set_user
|
||||
|
||||
def show
|
||||
render partial: 'api/v1/models/user.json.jbuilder', locals: { resource: @user }
|
||||
end
|
||||
def show; end
|
||||
|
||||
def update
|
||||
if password_params[:password].present?
|
||||
|
@ -15,19 +13,26 @@ class Api::V1::ProfilesController < Api::BaseController
|
|||
@user.update!(profile_params)
|
||||
end
|
||||
|
||||
def availability
|
||||
@user.account_users.find_by!(account_id: availability_params[:account_id]).update!(availability: availability_params[:availability])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_user
|
||||
@user = current_user
|
||||
end
|
||||
|
||||
def availability_params
|
||||
params.require(:profile).permit(:account_id, :availability)
|
||||
end
|
||||
|
||||
def profile_params
|
||||
params.require(:profile).permit(
|
||||
:email,
|
||||
:name,
|
||||
:display_name,
|
||||
:avatar,
|
||||
:availability,
|
||||
ui_settings: {}
|
||||
)
|
||||
end
|
||||
|
|
|
@ -161,9 +161,9 @@ export default {
|
|||
});
|
||||
},
|
||||
|
||||
updateAvailability({ availability }) {
|
||||
return axios.put(endPoints('profileUpdate').url, {
|
||||
profile: { availability },
|
||||
updateAvailability(availabilityData) {
|
||||
return axios.post(endPoints('availabilityUpdate').url, {
|
||||
profile: { ...availabilityData },
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -13,6 +13,9 @@ const endPoints = {
|
|||
profileUpdate: {
|
||||
url: '/api/v1/profile',
|
||||
},
|
||||
availabilityUpdate: {
|
||||
url: '/api/v1/profile/availability',
|
||||
},
|
||||
logout: {
|
||||
url: 'auth/sign_out',
|
||||
},
|
||||
|
|
|
@ -26,7 +26,9 @@
|
|||
color-scheme="secondary"
|
||||
class-names="status-change--dropdown-button"
|
||||
:is-disabled="status.disabled"
|
||||
@click="changeAvailabilityStatus(status.value)"
|
||||
@click="
|
||||
changeAvailabilityStatus(status.value, currentAccountId)
|
||||
"
|
||||
>
|
||||
<availability-status-badge :status="status.value" />
|
||||
{{ status.label }}
|
||||
|
@ -75,7 +77,8 @@ export default {
|
|||
|
||||
computed: {
|
||||
...mapGetters({
|
||||
currentUser: 'getCurrentUser',
|
||||
getCurrentUserAvailabilityStatus: 'getCurrentUserAvailabilityStatus',
|
||||
getCurrentAccountId: 'getCurrentAccountId',
|
||||
}),
|
||||
availabilityDisplayLabel() {
|
||||
const availabilityIndex = AVAILABILITY_STATUS_KEYS.findIndex(
|
||||
|
@ -85,8 +88,11 @@ export default {
|
|||
availabilityIndex
|
||||
];
|
||||
},
|
||||
currentAccountId() {
|
||||
return this.getCurrentAccountId;
|
||||
},
|
||||
currentUserAvailabilityStatus() {
|
||||
return this.currentUser.availability_status;
|
||||
return this.getCurrentUserAvailabilityStatus;
|
||||
},
|
||||
availabilityStatuses() {
|
||||
return this.$t('PROFILE_SETTINGS.FORM.AVAILABILITY.STATUSES_LIST').map(
|
||||
|
@ -108,16 +114,16 @@ export default {
|
|||
closeStatusMenu() {
|
||||
this.isStatusMenuOpened = false;
|
||||
},
|
||||
changeAvailabilityStatus(availability) {
|
||||
changeAvailabilityStatus(availability, accountId) {
|
||||
if (this.isUpdating) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isUpdating = true;
|
||||
|
||||
this.$store
|
||||
.dispatch('updateAvailability', {
|
||||
availability,
|
||||
availability: availability,
|
||||
account_id: accountId,
|
||||
})
|
||||
.finally(() => {
|
||||
this.isUpdating = false;
|
||||
|
|
|
@ -17,7 +17,8 @@ const i18nConfig = new VueI18n({
|
|||
});
|
||||
|
||||
describe('AvailabilityStatus', () => {
|
||||
const currentUser = { availability_status: 'online' };
|
||||
const currentAvailabilityStatus = 'online' ;
|
||||
const currentAccountId = '1';
|
||||
let store = null;
|
||||
let actions = null;
|
||||
let modules = null;
|
||||
|
@ -33,7 +34,8 @@ describe('AvailabilityStatus', () => {
|
|||
modules = {
|
||||
auth: {
|
||||
getters: {
|
||||
getCurrentUser: () => currentUser,
|
||||
getCurrentUserAvailabilityStatus: () => currentAvailabilityStatus,
|
||||
getCurrentAccountId: () => currentAccountId,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -77,7 +79,7 @@ describe('AvailabilityStatus', () => {
|
|||
|
||||
expect(actions.updateAvailability).toBeCalledWith(
|
||||
expect.any(Object),
|
||||
{ availability: 'offline' },
|
||||
{ availability: 'offline', account_id: currentAccountId },
|
||||
undefined
|
||||
);
|
||||
});
|
||||
|
|
|
@ -40,7 +40,11 @@ export const getters = {
|
|||
},
|
||||
|
||||
getCurrentUserAvailabilityStatus(_state) {
|
||||
return _state.currentUser.availability_status;
|
||||
const { accounts = [] } = _state.currentUser;
|
||||
const [currentAccount = {}] = accounts.filter(
|
||||
account => account.id === _state.currentAccountId
|
||||
);
|
||||
return currentAccount.availability_status;
|
||||
},
|
||||
|
||||
getCurrentAccountId(_state) {
|
||||
|
@ -125,14 +129,17 @@ export const actions = {
|
|||
}
|
||||
},
|
||||
|
||||
updateAvailability: ({ commit, dispatch }, { availability }) => {
|
||||
authAPI.updateAvailability({ availability }).then(response => {
|
||||
updateAvailability: async ({ commit, dispatch }, params) => {
|
||||
try {
|
||||
const response = await authAPI.updateAvailability(params);
|
||||
const userData = response.data;
|
||||
const { id, availability_status: availabilityStatus } = userData;
|
||||
const { id } = userData;
|
||||
setUser(userData, getHeaderExpiry(response));
|
||||
commit(types.default.SET_CURRENT_USER);
|
||||
dispatch('agents/updatePresence', { [id]: availabilityStatus });
|
||||
});
|
||||
dispatch('agents/updatePresence', { [id]: params.availability });
|
||||
} catch (error) {
|
||||
// Ignore error
|
||||
}
|
||||
},
|
||||
|
||||
setCurrentAccountId({ commit }, accountId) {
|
||||
|
|
|
@ -54,13 +54,16 @@ describe('#actions', () => {
|
|||
|
||||
describe('#updateAvailability', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.put.mockResolvedValue({
|
||||
data: { id: 1, name: 'John', availability_status: 'offline' },
|
||||
axios.post.mockResolvedValue({
|
||||
data: {
|
||||
id: 1,
|
||||
account_users: [{ account_id: 1, availability_status: 'offline' }],
|
||||
},
|
||||
headers: { expiry: 581842904 },
|
||||
});
|
||||
await actions.updateAvailability(
|
||||
{ commit, dispatch },
|
||||
{ availability: 'offline' }
|
||||
{ availability: 'offline', account_id: 1 },
|
||||
);
|
||||
expect(setUser).toHaveBeenCalledTimes(1);
|
||||
expect(commit.mock.calls).toEqual([[types.default.SET_CURRENT_USER]]);
|
||||
|
|
|
@ -21,7 +21,11 @@ describe('#getters', () => {
|
|||
it('get', () => {
|
||||
expect(
|
||||
getters.getCurrentUserAvailabilityStatus({
|
||||
currentUser: { id: 1, name: 'Pranav', availability_status: 'busy' },
|
||||
currentAccountId: 1,
|
||||
currentUser: {
|
||||
id: 1,
|
||||
accounts: [{ id: 1, availability_status: 'busy' }],
|
||||
},
|
||||
})
|
||||
).toEqual('busy');
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { createConsumer } from '@rails/actioncable';
|
||||
|
||||
const PRESENCE_INTERVAL = 60000;
|
||||
const PRESENCE_INTERVAL = 20000;
|
||||
|
||||
class BaseActionCableConnector {
|
||||
constructor(app, pubsubToken, websocketHost = '') {
|
||||
|
|
|
@ -2,14 +2,16 @@
|
|||
#
|
||||
# Table name: account_users
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# active_at :datetime
|
||||
# role :integer default("agent")
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# account_id :bigint
|
||||
# inviter_id :bigint
|
||||
# user_id :bigint
|
||||
# id :bigint not null, primary key
|
||||
# active_at :datetime
|
||||
# auto_offline :boolean default(TRUE), not null
|
||||
# availability :integer default("online"), not null
|
||||
# role :integer default("agent")
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# account_id :bigint
|
||||
# inviter_id :bigint
|
||||
# user_id :bigint
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
@ -24,15 +26,20 @@
|
|||
#
|
||||
|
||||
class AccountUser < ApplicationRecord
|
||||
include AvailabilityStatusable
|
||||
|
||||
belongs_to :account
|
||||
belongs_to :user
|
||||
belongs_to :inviter, class_name: 'User', optional: true
|
||||
|
||||
enum role: { agent: 0, administrator: 1 }
|
||||
enum availability: { online: 0, offline: 1, busy: 2 }
|
||||
|
||||
accepts_nested_attributes_for :account
|
||||
|
||||
after_create_commit :notify_creation, :create_notification_setting
|
||||
after_destroy :notify_deletion, :remove_user_from_account
|
||||
after_save :update_presence_in_redis, if: :saved_change_to_availability?
|
||||
|
||||
validates :user_id, uniqueness: { scope: :account_id }
|
||||
|
||||
|
@ -56,4 +63,8 @@ class AccountUser < ApplicationRecord
|
|||
def notify_deletion
|
||||
Rails.configuration.dispatcher.dispatch(AGENT_REMOVED, Time.zone.now, account: account)
|
||||
end
|
||||
|
||||
def update_presence_in_redis
|
||||
OnlineStatusTracker.set_status(account.id, user.id, availability)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,29 +2,29 @@ module AvailabilityStatusable
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
def online_presence?
|
||||
return if user_profile_page_context?
|
||||
|
||||
::OnlineStatusTracker.get_presence(availability_account_id, self.class.name, id)
|
||||
obj_id = is_a?(Contact) ? id : user_id
|
||||
::OnlineStatusTracker.get_presence(account_id, self.class.name, obj_id)
|
||||
end
|
||||
|
||||
def availability_status
|
||||
return availability if user_profile_page_context?
|
||||
return 'offline' unless online_presence?
|
||||
return 'online' if is_a? Contact
|
||||
|
||||
::OnlineStatusTracker.get_status(availability_account_id, id) || 'online'
|
||||
if is_a? Contact
|
||||
contact_availability_status
|
||||
else
|
||||
user_availability_status
|
||||
end
|
||||
end
|
||||
|
||||
def user_profile_page_context?
|
||||
# at the moment profile pages aren't account scoped
|
||||
# hence we will return availability attribute instead of true presence
|
||||
# we will revisit this later
|
||||
is_a?(User) && Current.account.blank?
|
||||
private
|
||||
|
||||
def contact_availability_status
|
||||
online_presence? ? 'online' : 'offline'
|
||||
end
|
||||
|
||||
def availability_account_id
|
||||
return account_id if is_a? Contact
|
||||
def user_availability_status
|
||||
# we are not considering presence in this case. Just returns the availability
|
||||
return availability unless auto_offline
|
||||
|
||||
Current.account.id
|
||||
# availability as a fallback in case the status is not present in redis
|
||||
online_presence? ? (::OnlineStatusTracker.get_status(account_id, user_id) || availability) : 'offline'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
|
||||
class User < ApplicationRecord
|
||||
include AccessTokenable
|
||||
include AvailabilityStatusable
|
||||
include Avatarable
|
||||
# Include default devise modules.
|
||||
include DeviseTokenAuth::Concerns::User
|
||||
|
@ -57,6 +56,8 @@ class User < ApplicationRecord
|
|||
:confirmable,
|
||||
:password_has_required_content
|
||||
|
||||
# TODO: remove in a future version once online status is moved to account users
|
||||
# remove the column availability from users
|
||||
enum availability: { online: 0, offline: 1, busy: 2 }
|
||||
|
||||
# The validation below has been commented out as it does not
|
||||
|
@ -89,8 +90,6 @@ class User < ApplicationRecord
|
|||
|
||||
before_validation :set_password_and_uid, on: :create
|
||||
|
||||
after_save :update_presence_in_redis, if: :saved_change_to_availability?
|
||||
|
||||
scope :order_by_full_name, -> { order('lower(name) ASC') }
|
||||
|
||||
def send_devise_notification(notification, *args)
|
||||
|
@ -141,6 +140,14 @@ class User < ApplicationRecord
|
|||
current_account_user&.role
|
||||
end
|
||||
|
||||
def availability_status
|
||||
current_account_user&.availability_status
|
||||
end
|
||||
|
||||
def auto_offline
|
||||
current_account_user&.auto_offline
|
||||
end
|
||||
|
||||
def inviter
|
||||
current_account_user&.inviter
|
||||
end
|
||||
|
@ -169,12 +176,4 @@ class User < ApplicationRecord
|
|||
type: 'user'
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_presence_in_redis
|
||||
accounts.each do |account|
|
||||
OnlineStatusTracker.set_status(account.id, id, availability)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
1
app/views/api/v1/accounts/agents/create.json.jbuilder
Normal file
1
app/views/api/v1/accounts/agents/create.json.jbuilder
Normal file
|
@ -0,0 +1 @@
|
|||
json.partial! 'api/v1/models/agent.json.jbuilder', resource: @user
|
1
app/views/api/v1/accounts/agents/update.json.jbuilder
Normal file
1
app/views/api/v1/accounts/agents/update.json.jbuilder
Normal file
|
@ -0,0 +1 @@
|
|||
json.partial! 'api/v1/models/agent.json.jbuilder', resource: @agent
|
|
@ -1,10 +1,11 @@
|
|||
json.id resource.id
|
||||
# could be nil for a deleted agent hence the safe operator before account id
|
||||
json.account_id resource.account&.id
|
||||
json.availability_status resource.availability_status
|
||||
json.auto_offline resource.auto_offline
|
||||
json.confirmed resource.confirmed?
|
||||
json.email resource.email
|
||||
json.available_name resource.available_name
|
||||
json.id resource.id
|
||||
json.custom_attributes resource.custom_attributes if resource.custom_attributes.present?
|
||||
json.name resource.name
|
||||
json.role resource.role
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
json.access_token resource.access_token.token
|
||||
json.account_id resource.active_account_user&.account_id
|
||||
json.availability_status resource.availability_status
|
||||
json.available_name resource.available_name
|
||||
json.avatar_url resource.avatar_url
|
||||
json.confirmed resource.confirmed?
|
||||
|
@ -22,5 +21,7 @@ json.accounts do
|
|||
json.name account_user.account.name
|
||||
json.active_at account_user.active_at
|
||||
json.role account_user.role
|
||||
json.availability_status account_user.availability_status
|
||||
json.auto_offline account_user.auto_offline
|
||||
end
|
||||
end
|
||||
|
|
1
app/views/api/v1/profiles/availability.jbuilder
Normal file
1
app/views/api/v1/profiles/availability.jbuilder
Normal file
|
@ -0,0 +1 @@
|
|||
json.partial! 'api/v1/models/user.json.jbuilder', resource: @user
|
1
app/views/api/v1/profiles/show.json.jbuilder
Normal file
1
app/views/api/v1/profiles/show.json.jbuilder
Normal file
|
@ -0,0 +1 @@
|
|||
json.partial! 'api/v1/models/user.json.jbuilder', resource: @user
|
|
@ -3,6 +3,6 @@ json.payload do
|
|||
json.id inbox_member.user.id
|
||||
json.name inbox_member.user.available_name
|
||||
json.avatar_url inbox_member.user.avatar_url
|
||||
json.availability_status inbox_member.user.availability_status
|
||||
json.availability_status inbox_member.user.account_users.find_by(account_id: @current_account.id).availability_status
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
json.access_token resource.access_token.token
|
||||
json.account_id resource.active_account_user&.account_id
|
||||
json.availability_status resource.availability_status
|
||||
json.available_name resource.available_name
|
||||
json.avatar_url resource.avatar_url
|
||||
json.confirmed resource.confirmed?
|
||||
|
|
|
@ -40,7 +40,7 @@ Rails.application.routes.draw do
|
|||
resource :contact_merge, only: [:create]
|
||||
end
|
||||
|
||||
resources :agents, except: [:show, :edit, :new]
|
||||
resources :agents, only: [:index, :create, :update, :destroy]
|
||||
resources :agent_bots, only: [:index, :create, :show, :update, :destroy]
|
||||
|
||||
resources :callbacks, only: [] do
|
||||
|
@ -159,7 +159,11 @@ Rails.application.routes.draw do
|
|||
resources :webhooks, only: [:create]
|
||||
end
|
||||
|
||||
resource :profile, only: [:show, :update]
|
||||
resource :profile, only: [:show, :update] do
|
||||
member do
|
||||
post :availability
|
||||
end
|
||||
end
|
||||
resource :notification_subscriptions, only: [:create]
|
||||
|
||||
namespace :widget do
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
class AddOnlineStatusToAccountUsers < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
change_table :account_users, bulk: true do |t|
|
||||
t.integer :availability, default: 0, null: false
|
||||
t.boolean :auto_offline, default: true, null: false
|
||||
end
|
||||
|
||||
update_existing_user_availability
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_existing_user_availability
|
||||
User.find_in_batches do |user_batch|
|
||||
user_batch.each do |user|
|
||||
availability = user.availability
|
||||
user.account_users.update(availability: availability)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -35,6 +35,8 @@ ActiveRecord::Schema.define(version: 2021_09_29_150415) do
|
|||
t.datetime "created_at", precision: 6, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
t.datetime "active_at"
|
||||
t.integer "availability", default: 0, null: false
|
||||
t.boolean "auto_offline", default: true, null: false
|
||||
t.index ["account_id", "user_id"], name: "uniq_user_id_per_account_id", unique: true
|
||||
t.index ["account_id"], name: "index_account_users_on_account_id"
|
||||
t.index ["user_id"], name: "index_account_users_on_user_id"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module OnlineStatusTracker
|
||||
PRESENCE_DURATION = 60.seconds
|
||||
PRESENCE_DURATION = 20.seconds
|
||||
|
||||
# presence : sorted set with timestamp as the score & object id as value
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ RSpec.describe 'Agents API', type: :request do
|
|||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'modifies an agent' do
|
||||
it 'modifies an agent name' do
|
||||
put "/api/v1/accounts/#{account.id}/agents/#{other_agent.id}",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
|
@ -103,6 +103,20 @@ RSpec.describe 'Agents API', type: :request do
|
|||
expect(response).to have_http_status(:success)
|
||||
expect(other_agent.reload.name).to eq(params[:name])
|
||||
end
|
||||
|
||||
it 'modifies an agents account user attributes' do
|
||||
put "/api/v1/accounts/#{account.id}/agents/#{other_agent.id}",
|
||||
params: { role: 'administrator', availability: 'busy', auto_offline: false },
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = JSON.parse(response.body)
|
||||
expect(response_data['role']).to eq('administrator')
|
||||
expect(response_data['availability_status']).to eq('busy')
|
||||
expect(response_data['auto_offline']).to eq(false)
|
||||
expect(other_agent.account_users.first.role).to eq('administrator')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -89,16 +89,6 @@ RSpec.describe 'Profile API', type: :request do
|
|||
expect(agent.avatar.attached?).to eq(true)
|
||||
end
|
||||
|
||||
it 'updates the availability status' do
|
||||
put '/api/v1/profile',
|
||||
params: { profile: { availability: 'offline' } },
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(::OnlineStatusTracker.get_status(account.id, agent.id)).to eq('offline')
|
||||
end
|
||||
|
||||
it 'updates the ui settings' do
|
||||
put '/api/v1/profile',
|
||||
params: { profile: { ui_settings: { is_contact_sidebar_open: false } } },
|
||||
|
@ -111,4 +101,28 @@ RSpec.describe 'Profile API', type: :request do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/profile/availability' do
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
post '/api/v1/profile/availability'
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, password: 'Test123!', account: account, role: :agent) }
|
||||
|
||||
it 'updates the availability status' do
|
||||
post '/api/v1/profile/availability',
|
||||
params: { profile: { availability: 'busy', account_id: account.id } },
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(::OnlineStatusTracker.get_status(account.id, agent.id)).to eq('busy')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: number
|
||||
type: integer
|
||||
uid:
|
||||
type: string
|
||||
name:
|
||||
|
@ -13,12 +13,19 @@ properties:
|
|||
email:
|
||||
type: string
|
||||
account_id:
|
||||
type: number
|
||||
type: integer
|
||||
role:
|
||||
type: string
|
||||
enum: ['agent', 'administrator']
|
||||
confirmed:
|
||||
type: boolean
|
||||
availability_status:
|
||||
type: string
|
||||
enum: ['available', 'busy', 'offline']
|
||||
description: The availability status of the agent computed by Chatwoot.
|
||||
auto_offline:
|
||||
type: boolean
|
||||
description: Whether the availability status of agent is configured to go offline automatically when away.
|
||||
custom_attributes:
|
||||
type: object
|
||||
description: Available for users who are created through platform APIs and has custom attributes associated.
|
||||
|
|
|
@ -53,6 +53,7 @@ x-tagGroups:
|
|||
- name: Application
|
||||
tags:
|
||||
- Account AgentBots
|
||||
- Agent
|
||||
- Contact
|
||||
- Conversation
|
||||
- Conversation Assignment
|
||||
|
|
42
swagger/paths/application/agents/create.yml
Normal file
42
swagger/paths/application/agents/create.yml
Normal file
|
@ -0,0 +1,42 @@
|
|||
tags:
|
||||
- Agent
|
||||
operationId: add-new-agent-to-account
|
||||
summary: Add a New Agent
|
||||
description: Add a new Agent to Account
|
||||
security:
|
||||
- userApiKey: []
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Full Name of the agent
|
||||
required: true
|
||||
email:
|
||||
type: string
|
||||
description: Email of the Agent
|
||||
required: true
|
||||
role:
|
||||
type: string
|
||||
enum: ['agent', 'administrator']
|
||||
description: Whether its administrator or agent
|
||||
required: true
|
||||
availability_status:
|
||||
type: string
|
||||
enum: ['available', 'busy', 'offline']
|
||||
description: The availability status of the agent.
|
||||
auto_offline:
|
||||
type: boolean
|
||||
description: Whether the availability status of agent is configured to go offline automatically when away.
|
||||
responses:
|
||||
200:
|
||||
description: Success
|
||||
schema:
|
||||
description: 'Newly Created Agent'
|
||||
$ref: '#/definitions/agent'
|
||||
403:
|
||||
description: Access denied
|
21
swagger/paths/application/agents/delete.yml
Normal file
21
swagger/paths/application/agents/delete.yml
Normal file
|
@ -0,0 +1,21 @@
|
|||
tags:
|
||||
- Agent
|
||||
operationId: delete-agent-from-account
|
||||
summary: Remove an Agent from Account
|
||||
description: Remove an Agent from Account
|
||||
security:
|
||||
- userApiKey: []
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
description: The ID of the agent to be deleted
|
||||
responses:
|
||||
200:
|
||||
description: Success
|
||||
404:
|
||||
description: Agent not found
|
||||
403:
|
||||
description: Access denied
|
17
swagger/paths/application/agents/index.yml
Normal file
17
swagger/paths/application/agents/index.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
tags:
|
||||
- Agent
|
||||
operationId: get-account-agents
|
||||
summary: List Agents in Account
|
||||
description: Get Details of Agents in an Account
|
||||
security:
|
||||
- userApiKey: []
|
||||
responses:
|
||||
200:
|
||||
description: Success
|
||||
schema:
|
||||
type: array
|
||||
description: 'Array of all active agents'
|
||||
items:
|
||||
$ref: '#/definitions/agent'
|
||||
403:
|
||||
description: Access denied
|
42
swagger/paths/application/agents/update.yml
Normal file
42
swagger/paths/application/agents/update.yml
Normal file
|
@ -0,0 +1,42 @@
|
|||
tags:
|
||||
- Agent
|
||||
operationId: update-agent-in-account
|
||||
summary: Update Agent in Account
|
||||
description: Update an Agent in Account
|
||||
security:
|
||||
- userApiKey: []
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
description: The ID of the agent to be updated.
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
role:
|
||||
type: string
|
||||
enum: ['agent', 'administrator']
|
||||
description: Whether its administrator or agent
|
||||
required: true
|
||||
availability_status:
|
||||
type: string
|
||||
enum: ['available', 'busy', 'offline']
|
||||
description: The availability status of the agent.
|
||||
auto_offline:
|
||||
type: boolean
|
||||
description: Whether the availability status of agent is configured to go offline automatically when away.
|
||||
responses:
|
||||
200:
|
||||
description: Success
|
||||
schema:
|
||||
description: 'The updated agent'
|
||||
$ref: '#/definitions/agent'
|
||||
404:
|
||||
description: Agent not found
|
||||
403:
|
||||
description: Access denied
|
|
@ -116,63 +116,76 @@ public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversat
|
|||
# ---------------- end of public api routes-----------#
|
||||
|
||||
# ------------ Application API routes ------------#
|
||||
# AgentBots
|
||||
|
||||
|
||||
# AgentBots
|
||||
/api/v1/accounts/{account_id}/agent_bots:
|
||||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
get:
|
||||
$ref: ./agent_bots/index.yml
|
||||
$ref: ./application/agent_bots/index.yml
|
||||
post:
|
||||
$ref: ./agent_bots/create.yml
|
||||
$ref: ./application/agent_bots/create.yml
|
||||
/api/v1/accounts/{account_id}/agent_bots/{id}:
|
||||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
- $ref: '#/parameters/agent_bot_id'
|
||||
get:
|
||||
$ref: './agent_bots/show.yml'
|
||||
$ref: './application/agent_bots/show.yml'
|
||||
patch:
|
||||
$ref: ./agent_bots/update.yml
|
||||
$ref: ./application/agent_bots/update.yml
|
||||
delete:
|
||||
$ref: ./agent_bots/delete.yml
|
||||
$ref: ./application/agent_bots/delete.yml
|
||||
|
||||
# Agents
|
||||
/api/v1/accounts/{account_id}/agents:
|
||||
get:
|
||||
$ref: ./application/agents/index.yml
|
||||
post:
|
||||
$ref: ./application/agents/create.yml
|
||||
/api/v1/accounts/{account_id}/agents/{id}:
|
||||
patch:
|
||||
$ref: ./application/agents/update.yml
|
||||
delete:
|
||||
$ref: ./application/agents/delete.yml
|
||||
|
||||
|
||||
# Contacts
|
||||
/api/v1/accounts/{account_id}/contacts:
|
||||
$ref: ./contact/list_create.yml
|
||||
$ref: ./application/contacts/list_create.yml
|
||||
/api/v1/accounts/{account_id}/contacts/{id}:
|
||||
$ref: ./contact/crud.yml
|
||||
$ref: ./application/contacts/crud.yml
|
||||
/api/v1/accounts/{account_id}/contacts/{id}/conversations:
|
||||
$ref: ./contact/conversations.yml
|
||||
$ref: ./application/contacts/conversations.yml
|
||||
/api/v1/accounts/{account_id}/contacts/search:
|
||||
$ref: ./contact/search.yml
|
||||
$ref: ./application/contacts/search.yml
|
||||
/api/v1/accounts/{account_id}/contacts/{id}/contact_inboxes:
|
||||
$ref: ./contact_inboxes/create.yml
|
||||
$ref: ./application/contact_inboxes/create.yml
|
||||
/api/v1/accounts/{account_id}/contacts/{id}/contactable_inboxes:
|
||||
$ref: ./contactable_inboxes/get.yml
|
||||
$ref: ./application/contactable_inboxes/get.yml
|
||||
|
||||
|
||||
# Conversations
|
||||
/api/v1/accounts/{account_id}/conversations:
|
||||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
$ref: ./conversation/index.yml
|
||||
$ref: ./application/conversation/index.yml
|
||||
/api/v1/accounts/{account_id}/conversations/:
|
||||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
$ref: ./conversation/create.yml
|
||||
$ref: ./application/conversation/create.yml
|
||||
/api/v1/accounts/{account_id}/conversations/{converstion_id}:
|
||||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
- $ref: '#/parameters/conversation_id'
|
||||
get:
|
||||
$ref: ./conversation/show.yml
|
||||
$ref: ./application/conversation/show.yml
|
||||
/api/v1/accounts/{account_id}/conversations/{conversation_id}/toggle_status:
|
||||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
- $ref: '#/parameters/conversation_id'
|
||||
post:
|
||||
$ref: ./conversation/toggle_status.yml
|
||||
$ref: ./application/conversation/toggle_status.yml
|
||||
|
||||
# Conversations Assignments
|
||||
|
||||
|
@ -181,7 +194,7 @@ public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversat
|
|||
- $ref: '#/parameters/account_id'
|
||||
- $ref: '#/parameters/conversation_id'
|
||||
post:
|
||||
$ref: ./conversation/assignments.yml
|
||||
$ref: ./application/conversation/assignments.yml
|
||||
|
||||
# Conversation Labels
|
||||
|
||||
|
@ -190,56 +203,56 @@ public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversat
|
|||
- $ref: '#/parameters/account_id'
|
||||
- $ref: '#/parameters/conversation_id'
|
||||
get:
|
||||
$ref: ./conversation/labels/index.yml
|
||||
$ref: ./application/conversation/labels/index.yml
|
||||
post:
|
||||
$ref: ./conversation/labels/create.yml
|
||||
$ref: ./application/conversation/labels/create.yml
|
||||
|
||||
|
||||
# Inboxes
|
||||
/api/v1/accounts/{account_id}/inboxes:
|
||||
$ref: ./inboxes/index.yml
|
||||
$ref: ./application/inboxes/index.yml
|
||||
/api/v1/accounts/{account_id}/inboxes/{id}/:
|
||||
$ref: ./inboxes/show.yml
|
||||
$ref: ./application/inboxes/show.yml
|
||||
/api/v1/accounts/{account_id}/inboxes/:
|
||||
$ref: ./inboxes/create.yml
|
||||
$ref: ./application/inboxes/create.yml
|
||||
/api/v1/accounts/{account_id}/inboxes/{id}:
|
||||
$ref: ./inboxes/update.yml
|
||||
$ref: ./application/inboxes/update.yml
|
||||
/api/v1/accounts/{account_id}/inboxes/{id}/agent_bot:
|
||||
$ref: ./inboxes/get_agent_bot.yml
|
||||
$ref: ./application/inboxes/get_agent_bot.yml
|
||||
/api/v1/accounts/{account_id}/inboxes/{id}/set_agent_bot:
|
||||
$ref: ./inboxes/set_agent_bot.yml
|
||||
$ref: ./application/inboxes/set_agent_bot.yml
|
||||
|
||||
# Inbox Members
|
||||
/api/v1/accounts/{account_id}/inbox_members:
|
||||
get:
|
||||
$ref: ./inboxes/inbox_members/show.yml
|
||||
$ref: ./application/inboxes/inbox_members/show.yml
|
||||
post:
|
||||
$ref: ./inboxes/inbox_members/create.yml
|
||||
$ref: ./application/inboxes/inbox_members/create.yml
|
||||
patch:
|
||||
$ref: ./inboxes/inbox_members/update.yml
|
||||
$ref: ./application/inboxes/inbox_members/update.yml
|
||||
delete:
|
||||
$ref: ./inboxes/inbox_members/delete.yml
|
||||
$ref: ./application/inboxes/inbox_members/delete.yml
|
||||
|
||||
|
||||
|
||||
# Messages
|
||||
/api/v1/accounts/{account_id}/conversations/{id}/messages:
|
||||
$ref: ./conversation/messages/create_attachment.yml
|
||||
$ref: ./application/conversation/messages/create_attachment.yml
|
||||
/api/v1/accounts/{account_id}/conversations/{converstion_id}/messages:
|
||||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
- $ref: '#/parameters/conversation_id'
|
||||
get:
|
||||
$ref: ./conversation/messages/index.yml
|
||||
$ref: ./application/conversation/messages/index.yml
|
||||
post:
|
||||
$ref: ./conversation/messages/create.yml
|
||||
$ref: ./application/conversation/messages/create.yml
|
||||
/api/v1/accounts/{account_id}/conversations/{conversation_id}/messages/{message_id}:
|
||||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
- $ref: '#/parameters/conversation_id'
|
||||
- $ref: '#/parameters/message_id'
|
||||
delete:
|
||||
$ref: ./conversation/messages/delete.yml
|
||||
$ref: ./application/conversation/messages/delete.yml
|
||||
|
||||
|
||||
|
||||
|
@ -248,14 +261,14 @@ public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversat
|
|||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
get:
|
||||
$ref: './integrations/apps/show.yml'
|
||||
$ref: './application/integrations/apps/show.yml'
|
||||
/api/v1/accounts/{account_id}/integrations/hooks:
|
||||
post:
|
||||
$ref: './integrations/hooks/create.yml'
|
||||
$ref: './application/integrations/hooks/create.yml'
|
||||
patch:
|
||||
$ref: ./integrations/hooks/update.yml
|
||||
$ref: ./application/integrations/hooks/update.yml
|
||||
delete:
|
||||
$ref: ./integrations/hooks/delete.yml
|
||||
$ref: ./application/integrations/hooks/delete.yml
|
||||
|
||||
|
||||
|
||||
|
@ -269,19 +282,19 @@ public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversat
|
|||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
get:
|
||||
$ref: ./teams/index.yml
|
||||
$ref: ./application/teams/index.yml
|
||||
post:
|
||||
$ref: ./teams/create.yml
|
||||
$ref: ./application/teams/create.yml
|
||||
/api/v1/accounts/{account_id}/teams/{id}:
|
||||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
- $ref: '#/parameters/team_id'
|
||||
get:
|
||||
$ref: './teams/show.yml'
|
||||
$ref: './application/teams/show.yml'
|
||||
patch:
|
||||
$ref: ./teams/update.yml
|
||||
$ref: ./application/teams/update.yml
|
||||
delete:
|
||||
$ref: ./teams/delete.yml
|
||||
$ref: ./application/teams/delete.yml
|
||||
|
||||
### Custom Filters goes here
|
||||
|
||||
|
@ -297,19 +310,19 @@ public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversat
|
|||
required: false
|
||||
description: The type of custom filter
|
||||
get:
|
||||
$ref: ./custom_filters/index.yml
|
||||
$ref: ./application/custom_filters/index.yml
|
||||
post:
|
||||
$ref: ./custom_filters/create.yml
|
||||
$ref: ./application/custom_filters/create.yml
|
||||
/api/v1/accounts/{account_id}/custom_filters/{custom_filter_id}:
|
||||
parameters:
|
||||
- $ref: '#/parameters/account_id'
|
||||
- $ref: '#/parameters/custom_filter_id'
|
||||
get:
|
||||
$ref: './custom_filters/show.yml'
|
||||
$ref: './application/custom_filters/show.yml'
|
||||
patch:
|
||||
$ref: ./custom_filters/update.yml
|
||||
$ref: ./application/custom_filters/update.yml
|
||||
delete:
|
||||
$ref: ./custom_filters/delete.yml
|
||||
$ref: ./application/custom_filters/delete.yml
|
||||
|
||||
### Reports
|
||||
|
||||
|
@ -335,7 +348,7 @@ public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversat
|
|||
type: string
|
||||
description: The timestamp from where report should stop.
|
||||
get:
|
||||
$ref: './reports/index.yml'
|
||||
$ref: './application/reports/index.yml'
|
||||
|
||||
# Summary
|
||||
/api/v2/accounts/{id}/reports/summary:
|
||||
|
@ -358,4 +371,4 @@ public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversat
|
|||
type: string
|
||||
description: The timestamp from where report should stop.
|
||||
get:
|
||||
$ref: './reports/summary.yml'
|
||||
$ref: './application/reports/summary.yml'
|
||||
|
|
|
@ -1103,6 +1103,219 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/accounts/{account_id}/agents": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Agent"
|
||||
],
|
||||
"operationId": "get-account-agents",
|
||||
"summary": "List Agents in Account",
|
||||
"description": "Get Details of Agents in an Account",
|
||||
"security": [
|
||||
{
|
||||
"userApiKey": [
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"description": "Array of all active agents",
|
||||
"items": {
|
||||
"$ref": "#/definitions/agent"
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Access denied"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"Agent"
|
||||
],
|
||||
"operationId": "add-new-agent-to-account",
|
||||
"summary": "Add a New Agent",
|
||||
"description": "Add a new Agent to Account",
|
||||
"security": [
|
||||
{
|
||||
"userApiKey": [
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Full Name of the agent",
|
||||
"required": true
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"description": "Email of the Agent",
|
||||
"required": true
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"agent",
|
||||
"administrator"
|
||||
],
|
||||
"description": "Whether its administrator or agent",
|
||||
"required": true
|
||||
},
|
||||
"availability_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"available",
|
||||
"busy",
|
||||
"offline"
|
||||
],
|
||||
"description": "The availability status of the agent."
|
||||
},
|
||||
"auto_offline": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the availability status of agent is configured to go offline automatically when away."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/agent"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Access denied"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/accounts/{account_id}/agents/{id}": {
|
||||
"patch": {
|
||||
"tags": [
|
||||
"Agent"
|
||||
],
|
||||
"operationId": "update-agent-in-account",
|
||||
"summary": "Update Agent in Account",
|
||||
"description": "Update an Agent in Account",
|
||||
"security": [
|
||||
{
|
||||
"userApiKey": [
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
},
|
||||
"required": true,
|
||||
"description": "The ID of the agent to be updated."
|
||||
},
|
||||
{
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"agent",
|
||||
"administrator"
|
||||
],
|
||||
"description": "Whether its administrator or agent",
|
||||
"required": true
|
||||
},
|
||||
"availability_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"available",
|
||||
"busy",
|
||||
"offline"
|
||||
],
|
||||
"description": "The availability status of the agent."
|
||||
},
|
||||
"auto_offline": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the availability status of agent is configured to go offline automatically when away."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/agent"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Agent not found"
|
||||
},
|
||||
"403": {
|
||||
"description": "Access denied"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Agent"
|
||||
],
|
||||
"operationId": "delete-agent-from-account",
|
||||
"summary": "Remove an Agent from Account",
|
||||
"description": "Remove an Agent from Account",
|
||||
"security": [
|
||||
{
|
||||
"userApiKey": [
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
},
|
||||
"required": true,
|
||||
"description": "The ID of the agent to be deleted"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success"
|
||||
},
|
||||
"404": {
|
||||
"description": "Agent not found"
|
||||
},
|
||||
"403": {
|
||||
"description": "Access denied"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/accounts/{account_id}/contacts": {
|
||||
"get": {
|
||||
"tags": [
|
||||
|
@ -3432,7 +3645,7 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number"
|
||||
"type": "integer"
|
||||
},
|
||||
"uid": {
|
||||
"type": "string"
|
||||
|
@ -3450,7 +3663,7 @@
|
|||
"type": "string"
|
||||
},
|
||||
"account_id": {
|
||||
"type": "number"
|
||||
"type": "integer"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
|
@ -3462,6 +3675,19 @@
|
|||
"confirmed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"availability_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"available",
|
||||
"busy",
|
||||
"offline"
|
||||
],
|
||||
"description": "The availability status of the agent computed by Chatwoot."
|
||||
},
|
||||
"auto_offline": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the availability status of agent is configured to go offline automatically when away."
|
||||
},
|
||||
"custom_attributes": {
|
||||
"type": "object",
|
||||
"description": "Available for users who are created through platform APIs and has custom attributes associated."
|
||||
|
@ -4556,6 +4782,7 @@
|
|||
"name": "Application",
|
||||
"tags": [
|
||||
"Account AgentBots",
|
||||
"Agent",
|
||||
"Contact",
|
||||
"Conversation",
|
||||
"Conversation Assignment",
|
||||
|
|
Loading…
Reference in a new issue