diff --git a/app/controllers/api/v1/accounts/agents_controller.rb b/app/controllers/api/v1/accounts/agents_controller.rb index 334844de9..a406e0cf3 100644 --- a/app/controllers/api/v1/accounts/agents_controller.rb +++ b/app/controllers/api/v1/accounts/agents_controller.rb @@ -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 diff --git a/app/controllers/api/v1/profiles_controller.rb b/app/controllers/api/v1/profiles_controller.rb index 5805f49ed..a92c479bc 100644 --- a/app/controllers/api/v1/profiles_controller.rb +++ b/app/controllers/api/v1/profiles_controller.rb @@ -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 diff --git a/app/javascript/dashboard/api/auth.js b/app/javascript/dashboard/api/auth.js index 558eb4933..c41a43624 100644 --- a/app/javascript/dashboard/api/auth.js +++ b/app/javascript/dashboard/api/auth.js @@ -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 }, }); }, }; diff --git a/app/javascript/dashboard/api/endPoints.js b/app/javascript/dashboard/api/endPoints.js index 8df609f70..0b801fdb3 100644 --- a/app/javascript/dashboard/api/endPoints.js +++ b/app/javascript/dashboard/api/endPoints.js @@ -13,6 +13,9 @@ const endPoints = { profileUpdate: { url: '/api/v1/profile', }, + availabilityUpdate: { + url: '/api/v1/profile/availability', + }, logout: { url: 'auth/sign_out', }, diff --git a/app/javascript/dashboard/components/layout/AvailabilityStatus.vue b/app/javascript/dashboard/components/layout/AvailabilityStatus.vue index 8587bacc8..ec26b8bce 100644 --- a/app/javascript/dashboard/components/layout/AvailabilityStatus.vue +++ b/app/javascript/dashboard/components/layout/AvailabilityStatus.vue @@ -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) + " > {{ 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; diff --git a/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js b/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js index d96f9761d..2954b837d 100644 --- a/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js +++ b/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js @@ -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 ); }); diff --git a/app/javascript/dashboard/store/modules/auth.js b/app/javascript/dashboard/store/modules/auth.js index e0691049c..0805b35db 100644 --- a/app/javascript/dashboard/store/modules/auth.js +++ b/app/javascript/dashboard/store/modules/auth.js @@ -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) { diff --git a/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js b/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js index adbca0d94..fe503e3ea 100644 --- a/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js +++ b/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js @@ -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]]); diff --git a/app/javascript/dashboard/store/modules/specs/auth/getters.spec.js b/app/javascript/dashboard/store/modules/specs/auth/getters.spec.js index c934d3824..dd87cd79d 100644 --- a/app/javascript/dashboard/store/modules/specs/auth/getters.spec.js +++ b/app/javascript/dashboard/store/modules/specs/auth/getters.spec.js @@ -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'); }); diff --git a/app/javascript/shared/helpers/BaseActionCableConnector.js b/app/javascript/shared/helpers/BaseActionCableConnector.js index 89b3ed6b0..f92ed9c6b 100644 --- a/app/javascript/shared/helpers/BaseActionCableConnector.js +++ b/app/javascript/shared/helpers/BaseActionCableConnector.js @@ -1,6 +1,6 @@ import { createConsumer } from '@rails/actioncable'; -const PRESENCE_INTERVAL = 60000; +const PRESENCE_INTERVAL = 20000; class BaseActionCableConnector { constructor(app, pubsubToken, websocketHost = '') { diff --git a/app/models/account_user.rb b/app/models/account_user.rb index 6c5e89e3c..8f06253fc 100644 --- a/app/models/account_user.rb +++ b/app/models/account_user.rb @@ -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 diff --git a/app/models/concerns/availability_statusable.rb b/app/models/concerns/availability_statusable.rb index 11d1e438e..9cfe6bfec 100644 --- a/app/models/concerns/availability_statusable.rb +++ b/app/models/concerns/availability_statusable.rb @@ -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 diff --git a/app/models/user.rb b/app/models/user.rb index 89ed7be84..214658869 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -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 diff --git a/app/views/api/v1/accounts/agents/create.json.jbuilder b/app/views/api/v1/accounts/agents/create.json.jbuilder new file mode 100644 index 000000000..7f22d270d --- /dev/null +++ b/app/views/api/v1/accounts/agents/create.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'api/v1/models/agent.json.jbuilder', resource: @user diff --git a/app/views/api/v1/accounts/agents/update.json.jbuilder b/app/views/api/v1/accounts/agents/update.json.jbuilder new file mode 100644 index 000000000..38328ca08 --- /dev/null +++ b/app/views/api/v1/accounts/agents/update.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'api/v1/models/agent.json.jbuilder', resource: @agent diff --git a/app/views/api/v1/models/_agent.json.jbuilder b/app/views/api/v1/models/_agent.json.jbuilder index 071fbbcd8..fd7119ca5 100644 --- a/app/views/api/v1/models/_agent.json.jbuilder +++ b/app/views/api/v1/models/_agent.json.jbuilder @@ -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 diff --git a/app/views/api/v1/models/_user.json.jbuilder b/app/views/api/v1/models/_user.json.jbuilder index 5c0cdeec9..745dd0618 100644 --- a/app/views/api/v1/models/_user.json.jbuilder +++ b/app/views/api/v1/models/_user.json.jbuilder @@ -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 diff --git a/app/views/api/v1/profiles/availability.jbuilder b/app/views/api/v1/profiles/availability.jbuilder new file mode 100644 index 000000000..5a6dc2dad --- /dev/null +++ b/app/views/api/v1/profiles/availability.jbuilder @@ -0,0 +1 @@ +json.partial! 'api/v1/models/user.json.jbuilder', resource: @user diff --git a/app/views/api/v1/profiles/show.json.jbuilder b/app/views/api/v1/profiles/show.json.jbuilder new file mode 100644 index 000000000..5a6dc2dad --- /dev/null +++ b/app/views/api/v1/profiles/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'api/v1/models/user.json.jbuilder', resource: @user diff --git a/app/views/api/v1/widget/inbox_members/index.json.jbuilder b/app/views/api/v1/widget/inbox_members/index.json.jbuilder index af38fc1ee..417c23756 100644 --- a/app/views/api/v1/widget/inbox_members/index.json.jbuilder +++ b/app/views/api/v1/widget/inbox_members/index.json.jbuilder @@ -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 diff --git a/app/views/platform/api/v1/models/_user.json.jbuilder b/app/views/platform/api/v1/models/_user.json.jbuilder index 1ec708b8d..4c50efaaa 100644 --- a/app/views/platform/api/v1/models/_user.json.jbuilder +++ b/app/views/platform/api/v1/models/_user.json.jbuilder @@ -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? diff --git a/config/routes.rb b/config/routes.rb index 9a210473e..c825911d7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/db/migrate/20210923190418_add_online_status_to_account_users.rb b/db/migrate/20210923190418_add_online_status_to_account_users.rb new file mode 100644 index 000000000..eccc9be1c --- /dev/null +++ b/db/migrate/20210923190418_add_online_status_to_account_users.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index 7a954f94d..5f23ac780 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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" diff --git a/lib/online_status_tracker.rb b/lib/online_status_tracker.rb index 42bc0dca0..8688c4251 100644 --- a/lib/online_status_tracker.rb +++ b/lib/online_status_tracker.rb @@ -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 diff --git a/spec/controllers/api/v1/accounts/agents_controller_spec.rb b/spec/controllers/api/v1/accounts/agents_controller_spec.rb index 872b14669..4d8aa4d65 100644 --- a/spec/controllers/api/v1/accounts/agents_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/agents_controller_spec.rb @@ -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 diff --git a/spec/controllers/api/v1/profiles_controller_spec.rb b/spec/controllers/api/v1/profiles_controller_spec.rb index 3247b5f83..53de5bcfe 100644 --- a/spec/controllers/api/v1/profiles_controller_spec.rb +++ b/spec/controllers/api/v1/profiles_controller_spec.rb @@ -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 diff --git a/swagger/definitions/resource/agent.yml b/swagger/definitions/resource/agent.yml index 0473d3d87..e3d506a3b 100644 --- a/swagger/definitions/resource/agent.yml +++ b/swagger/definitions/resource/agent.yml @@ -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. diff --git a/swagger/index.yml b/swagger/index.yml index 2d1ef704a..908c27509 100644 --- a/swagger/index.yml +++ b/swagger/index.yml @@ -53,6 +53,7 @@ x-tagGroups: - name: Application tags: - Account AgentBots + - Agent - Contact - Conversation - Conversation Assignment diff --git a/swagger/paths/agent_bots/create.yml b/swagger/paths/application/agent_bots/create.yml similarity index 100% rename from swagger/paths/agent_bots/create.yml rename to swagger/paths/application/agent_bots/create.yml diff --git a/swagger/paths/agent_bots/delete.yml b/swagger/paths/application/agent_bots/delete.yml similarity index 100% rename from swagger/paths/agent_bots/delete.yml rename to swagger/paths/application/agent_bots/delete.yml diff --git a/swagger/paths/agent_bots/index.yml b/swagger/paths/application/agent_bots/index.yml similarity index 100% rename from swagger/paths/agent_bots/index.yml rename to swagger/paths/application/agent_bots/index.yml diff --git a/swagger/paths/agent_bots/show.yml b/swagger/paths/application/agent_bots/show.yml similarity index 100% rename from swagger/paths/agent_bots/show.yml rename to swagger/paths/application/agent_bots/show.yml diff --git a/swagger/paths/agent_bots/update.yml b/swagger/paths/application/agent_bots/update.yml similarity index 100% rename from swagger/paths/agent_bots/update.yml rename to swagger/paths/application/agent_bots/update.yml diff --git a/swagger/paths/application/agents/create.yml b/swagger/paths/application/agents/create.yml new file mode 100644 index 000000000..de7381830 --- /dev/null +++ b/swagger/paths/application/agents/create.yml @@ -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 diff --git a/swagger/paths/application/agents/delete.yml b/swagger/paths/application/agents/delete.yml new file mode 100644 index 000000000..533d3f1ca --- /dev/null +++ b/swagger/paths/application/agents/delete.yml @@ -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 diff --git a/swagger/paths/application/agents/index.yml b/swagger/paths/application/agents/index.yml new file mode 100644 index 000000000..026893a4b --- /dev/null +++ b/swagger/paths/application/agents/index.yml @@ -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 diff --git a/swagger/paths/application/agents/update.yml b/swagger/paths/application/agents/update.yml new file mode 100644 index 000000000..8e4745348 --- /dev/null +++ b/swagger/paths/application/agents/update.yml @@ -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 \ No newline at end of file diff --git a/swagger/paths/contact_inboxes/create.yml b/swagger/paths/application/contact_inboxes/create.yml similarity index 100% rename from swagger/paths/contact_inboxes/create.yml rename to swagger/paths/application/contact_inboxes/create.yml diff --git a/swagger/paths/contactable_inboxes/get.yml b/swagger/paths/application/contactable_inboxes/get.yml similarity index 100% rename from swagger/paths/contactable_inboxes/get.yml rename to swagger/paths/application/contactable_inboxes/get.yml diff --git a/swagger/paths/contact/conversations.yml b/swagger/paths/application/contacts/conversations.yml similarity index 100% rename from swagger/paths/contact/conversations.yml rename to swagger/paths/application/contacts/conversations.yml diff --git a/swagger/paths/contact/crud.yml b/swagger/paths/application/contacts/crud.yml similarity index 100% rename from swagger/paths/contact/crud.yml rename to swagger/paths/application/contacts/crud.yml diff --git a/swagger/paths/contact/list_create.yml b/swagger/paths/application/contacts/list_create.yml similarity index 100% rename from swagger/paths/contact/list_create.yml rename to swagger/paths/application/contacts/list_create.yml diff --git a/swagger/paths/contact/search.yml b/swagger/paths/application/contacts/search.yml similarity index 100% rename from swagger/paths/contact/search.yml rename to swagger/paths/application/contacts/search.yml diff --git a/swagger/paths/conversation/assignments.yml b/swagger/paths/application/conversation/assignments.yml similarity index 100% rename from swagger/paths/conversation/assignments.yml rename to swagger/paths/application/conversation/assignments.yml diff --git a/swagger/paths/conversation/create.yml b/swagger/paths/application/conversation/create.yml similarity index 100% rename from swagger/paths/conversation/create.yml rename to swagger/paths/application/conversation/create.yml diff --git a/swagger/paths/conversation/index.yml b/swagger/paths/application/conversation/index.yml similarity index 100% rename from swagger/paths/conversation/index.yml rename to swagger/paths/application/conversation/index.yml diff --git a/swagger/paths/conversation/labels/create.yml b/swagger/paths/application/conversation/labels/create.yml similarity index 100% rename from swagger/paths/conversation/labels/create.yml rename to swagger/paths/application/conversation/labels/create.yml diff --git a/swagger/paths/conversation/labels/index.yml b/swagger/paths/application/conversation/labels/index.yml similarity index 100% rename from swagger/paths/conversation/labels/index.yml rename to swagger/paths/application/conversation/labels/index.yml diff --git a/swagger/paths/conversation/messages/create.yml b/swagger/paths/application/conversation/messages/create.yml similarity index 100% rename from swagger/paths/conversation/messages/create.yml rename to swagger/paths/application/conversation/messages/create.yml diff --git a/swagger/paths/conversation/messages/create_attachment.yml b/swagger/paths/application/conversation/messages/create_attachment.yml similarity index 100% rename from swagger/paths/conversation/messages/create_attachment.yml rename to swagger/paths/application/conversation/messages/create_attachment.yml diff --git a/swagger/paths/conversation/messages/delete.yml b/swagger/paths/application/conversation/messages/delete.yml similarity index 100% rename from swagger/paths/conversation/messages/delete.yml rename to swagger/paths/application/conversation/messages/delete.yml diff --git a/swagger/paths/conversation/messages/index.yml b/swagger/paths/application/conversation/messages/index.yml similarity index 100% rename from swagger/paths/conversation/messages/index.yml rename to swagger/paths/application/conversation/messages/index.yml diff --git a/swagger/paths/conversation/show.yml b/swagger/paths/application/conversation/show.yml similarity index 100% rename from swagger/paths/conversation/show.yml rename to swagger/paths/application/conversation/show.yml diff --git a/swagger/paths/conversation/toggle_status.yml b/swagger/paths/application/conversation/toggle_status.yml similarity index 100% rename from swagger/paths/conversation/toggle_status.yml rename to swagger/paths/application/conversation/toggle_status.yml diff --git a/swagger/paths/conversation/update_last_seen.yml b/swagger/paths/application/conversation/update_last_seen.yml similarity index 100% rename from swagger/paths/conversation/update_last_seen.yml rename to swagger/paths/application/conversation/update_last_seen.yml diff --git a/swagger/paths/custom_filters/create.yml b/swagger/paths/application/custom_filters/create.yml similarity index 100% rename from swagger/paths/custom_filters/create.yml rename to swagger/paths/application/custom_filters/create.yml diff --git a/swagger/paths/custom_filters/delete.yml b/swagger/paths/application/custom_filters/delete.yml similarity index 100% rename from swagger/paths/custom_filters/delete.yml rename to swagger/paths/application/custom_filters/delete.yml diff --git a/swagger/paths/custom_filters/index.yml b/swagger/paths/application/custom_filters/index.yml similarity index 100% rename from swagger/paths/custom_filters/index.yml rename to swagger/paths/application/custom_filters/index.yml diff --git a/swagger/paths/custom_filters/show.yml b/swagger/paths/application/custom_filters/show.yml similarity index 100% rename from swagger/paths/custom_filters/show.yml rename to swagger/paths/application/custom_filters/show.yml diff --git a/swagger/paths/custom_filters/update.yml b/swagger/paths/application/custom_filters/update.yml similarity index 100% rename from swagger/paths/custom_filters/update.yml rename to swagger/paths/application/custom_filters/update.yml diff --git a/swagger/paths/inboxes/create.yml b/swagger/paths/application/inboxes/create.yml similarity index 100% rename from swagger/paths/inboxes/create.yml rename to swagger/paths/application/inboxes/create.yml diff --git a/swagger/paths/inboxes/get_agent_bot.yml b/swagger/paths/application/inboxes/get_agent_bot.yml similarity index 100% rename from swagger/paths/inboxes/get_agent_bot.yml rename to swagger/paths/application/inboxes/get_agent_bot.yml diff --git a/swagger/paths/inboxes/inbox_members/create.yml b/swagger/paths/application/inboxes/inbox_members/create.yml similarity index 100% rename from swagger/paths/inboxes/inbox_members/create.yml rename to swagger/paths/application/inboxes/inbox_members/create.yml diff --git a/swagger/paths/inboxes/inbox_members/delete.yml b/swagger/paths/application/inboxes/inbox_members/delete.yml similarity index 100% rename from swagger/paths/inboxes/inbox_members/delete.yml rename to swagger/paths/application/inboxes/inbox_members/delete.yml diff --git a/swagger/paths/inboxes/inbox_members/show.yml b/swagger/paths/application/inboxes/inbox_members/show.yml similarity index 100% rename from swagger/paths/inboxes/inbox_members/show.yml rename to swagger/paths/application/inboxes/inbox_members/show.yml diff --git a/swagger/paths/inboxes/inbox_members/update.yml b/swagger/paths/application/inboxes/inbox_members/update.yml similarity index 100% rename from swagger/paths/inboxes/inbox_members/update.yml rename to swagger/paths/application/inboxes/inbox_members/update.yml diff --git a/swagger/paths/inboxes/index.yml b/swagger/paths/application/inboxes/index.yml similarity index 100% rename from swagger/paths/inboxes/index.yml rename to swagger/paths/application/inboxes/index.yml diff --git a/swagger/paths/inboxes/set_agent_bot.yml b/swagger/paths/application/inboxes/set_agent_bot.yml similarity index 100% rename from swagger/paths/inboxes/set_agent_bot.yml rename to swagger/paths/application/inboxes/set_agent_bot.yml diff --git a/swagger/paths/inboxes/show.yml b/swagger/paths/application/inboxes/show.yml similarity index 100% rename from swagger/paths/inboxes/show.yml rename to swagger/paths/application/inboxes/show.yml diff --git a/swagger/paths/inboxes/update.yml b/swagger/paths/application/inboxes/update.yml similarity index 100% rename from swagger/paths/inboxes/update.yml rename to swagger/paths/application/inboxes/update.yml diff --git a/swagger/paths/integrations/apps/show.yml b/swagger/paths/application/integrations/apps/show.yml similarity index 100% rename from swagger/paths/integrations/apps/show.yml rename to swagger/paths/application/integrations/apps/show.yml diff --git a/swagger/paths/integrations/hooks/create.yml b/swagger/paths/application/integrations/hooks/create.yml similarity index 100% rename from swagger/paths/integrations/hooks/create.yml rename to swagger/paths/application/integrations/hooks/create.yml diff --git a/swagger/paths/integrations/hooks/delete.yml b/swagger/paths/application/integrations/hooks/delete.yml similarity index 100% rename from swagger/paths/integrations/hooks/delete.yml rename to swagger/paths/application/integrations/hooks/delete.yml diff --git a/swagger/paths/integrations/hooks/update.yml b/swagger/paths/application/integrations/hooks/update.yml similarity index 100% rename from swagger/paths/integrations/hooks/update.yml rename to swagger/paths/application/integrations/hooks/update.yml diff --git a/swagger/paths/reports/index.yml b/swagger/paths/application/reports/index.yml similarity index 100% rename from swagger/paths/reports/index.yml rename to swagger/paths/application/reports/index.yml diff --git a/swagger/paths/reports/summary.yml b/swagger/paths/application/reports/summary.yml similarity index 100% rename from swagger/paths/reports/summary.yml rename to swagger/paths/application/reports/summary.yml diff --git a/swagger/paths/teams/create.yml b/swagger/paths/application/teams/create.yml similarity index 100% rename from swagger/paths/teams/create.yml rename to swagger/paths/application/teams/create.yml diff --git a/swagger/paths/teams/delete.yml b/swagger/paths/application/teams/delete.yml similarity index 100% rename from swagger/paths/teams/delete.yml rename to swagger/paths/application/teams/delete.yml diff --git a/swagger/paths/teams/index.yml b/swagger/paths/application/teams/index.yml similarity index 100% rename from swagger/paths/teams/index.yml rename to swagger/paths/application/teams/index.yml diff --git a/swagger/paths/teams/show.yml b/swagger/paths/application/teams/show.yml similarity index 100% rename from swagger/paths/teams/show.yml rename to swagger/paths/application/teams/show.yml diff --git a/swagger/paths/teams/update.yml b/swagger/paths/application/teams/update.yml similarity index 100% rename from swagger/paths/teams/update.yml rename to swagger/paths/application/teams/update.yml diff --git a/swagger/paths/index.yml b/swagger/paths/index.yml index 4324b2504..4936bc1b7 100644 --- a/swagger/paths/index.yml +++ b/swagger/paths/index.yml @@ -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' diff --git a/swagger/swagger.json b/swagger/swagger.json index 450c18f4d..0d8570d99 100644 --- a/swagger/swagger.json +++ b/swagger/swagger.json @@ -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",