From 22d1c8baf2dc66aba52de9813fd71ca00e4cdb1a Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Tue, 14 Sep 2021 11:55:02 +0530 Subject: [PATCH] Chore: Inbox Members API improvements (#3008) - New Inbox Member APIs - Return JSON errors for Platform APIs --- .../v1/accounts/inbox_members_controller.rb | 34 +- .../api/v1/accounts/inboxes_controller.rb | 2 +- app/controllers/application_controller.rb | 41 +-- .../concerns/request_exception_handler.rb | 47 +++ .../platform/api/v1/users_controller.rb | 2 +- app/controllers/platform_controller.rb | 2 + app/controllers/public_controller.rb | 1 + app/javascript/dashboard/api/inboxMembers.js | 4 +- .../dashboard/store/modules/inboxMembers.js | 2 +- app/models/inbox.rb | 2 +- .../inbox_members/create.json.jbuilder | 5 + .../inbox_members/update.json.jbuilder | 5 + config/routes.rb | 7 +- .../accounts/inbox_members_controller_spec.rb | 310 ++++++++++++++---- swagger/definitions/index.yml | 2 + swagger/definitions/resource/agent.yml | 25 ++ swagger/parameters/inbox_id.yml | 6 + swagger/parameters/index.yml | 3 + .../paths/inboxes/inbox_members/create.yml | 36 ++ .../paths/inboxes/inbox_members/delete.yml | 31 ++ swagger/paths/inboxes/inbox_members/show.yml | 21 ++ .../paths/inboxes/inbox_members/update.yml | 36 ++ swagger/paths/inboxes/show.yml | 2 +- swagger/paths/index.yml | 14 +- swagger/swagger.json | 258 ++++++++++++++- 25 files changed, 767 insertions(+), 131 deletions(-) create mode 100644 app/controllers/concerns/request_exception_handler.rb create mode 100644 app/views/api/v1/accounts/inbox_members/create.json.jbuilder create mode 100644 app/views/api/v1/accounts/inbox_members/update.json.jbuilder create mode 100644 swagger/definitions/resource/agent.yml create mode 100644 swagger/parameters/inbox_id.yml create mode 100644 swagger/paths/inboxes/inbox_members/create.yml create mode 100644 swagger/paths/inboxes/inbox_members/delete.yml create mode 100644 swagger/paths/inboxes/inbox_members/show.yml create mode 100644 swagger/paths/inboxes/inbox_members/update.yml diff --git a/app/controllers/api/v1/accounts/inbox_members_controller.rb b/app/controllers/api/v1/accounts/inbox_members_controller.rb index c5fb3486b..591aa5637 100644 --- a/app/controllers/api/v1/accounts/inbox_members_controller.rb +++ b/app/controllers/api/v1/accounts/inbox_members_controller.rb @@ -1,26 +1,40 @@ class Api::V1::Accounts::InboxMembersController < Api::V1::Accounts::BaseController - before_action :fetch_inbox, only: [:create, :show] - before_action :current_agents_ids, only: [:create] + before_action :fetch_inbox + before_action :current_agents_ids, only: [:update] def create authorize @inbox, :create? - begin - # update also done via same action - update_agents_list - head :ok - rescue StandardError => e - Rails.logger.debug { "Rescued: #{e.inspect}" } - render_could_not_create_error('Could not add agents to inbox') + ActiveRecord::Base.transaction do + params[:user_ids].map { |user_id| @inbox.add_member(user_id) } end + fetch_updated_agents end def show authorize @inbox, :show? - @agents = Current.account.users.where(id: @inbox.members.select(:user_id)) + fetch_updated_agents + end + + def update + authorize @inbox, :update? + update_agents_list + fetch_updated_agents + end + + def destroy + authorize @inbox, :destroy? + ActiveRecord::Base.transaction do + params[:user_ids].map { |user_id| @inbox.remove_member(user_id) } + end + head :ok end private + def fetch_updated_agents + @agents = Current.account.users.where(id: @inbox.members.select(:user_id)) + end + def update_agents_list # get all the user_ids which the inbox currently has as members. # get the list of user_ids from params diff --git a/app/controllers/api/v1/accounts/inboxes_controller.rb b/app/controllers/api/v1/accounts/inboxes_controller.rb index f9a6ce154..cb01fc380 100644 --- a/app/controllers/api/v1/accounts/inboxes_controller.rb +++ b/app/controllers/api/v1/accounts/inboxes_controller.rb @@ -43,7 +43,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController @inbox.update_working_hours(params.permit(working_hours: Inbox::OFFISABLE_ATTRS)[:working_hours]) if params[:working_hours] channel_attributes = get_channel_attributes(@inbox.channel_type) - @inbox.channel.update!(permitted_params(channel_attributes)[:channel]) + @inbox.channel.update!(permitted_params(channel_attributes)[:channel]) if permitted_params(channel_attributes)[:channel].present? update_channel_feature_flags end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d25f88269..0a1c672ec 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,5 +1,6 @@ class ApplicationController < ActionController::Base include DeviseTokenAuth::Concerns::SetUserByToken + include RequestExceptionHandler include Pundit include SwitchLocale @@ -9,22 +10,8 @@ class ApplicationController < ActionController::Base around_action :switch_locale around_action :handle_with_exception, unless: :devise_controller? - rescue_from ActiveRecord::RecordInvalid, with: :render_record_invalid - private - def handle_with_exception - yield - rescue ActiveRecord::RecordNotFound => e - Sentry.capture_exception(e) - render_not_found_error('Resource could not be found') - rescue Pundit::NotAuthorizedError - render_unauthorized('You are not authorized to do this action') - ensure - # to address the thread variable leak issues in Puma/Thin webserver - Current.reset - end - def set_current_user @user ||= current_user Current.user = @user @@ -34,32 +21,6 @@ class ApplicationController < ActionController::Base @subscription ||= Current.account.subscription end - def render_unauthorized(message) - render json: { error: message }, status: :unauthorized - end - - def render_not_found_error(message) - render json: { error: message }, status: :not_found - end - - def render_could_not_create_error(message) - render json: { error: message }, status: :unprocessable_entity - end - - def render_internal_server_error(message) - render json: { error: message }, status: :internal_server_error - end - - def render_record_invalid(exception) - render json: { - message: exception.record.errors.full_messages.join(', ') - }, status: :unprocessable_entity - end - - def render_error_response(exception) - render json: exception.to_hash, status: exception.http_status - end - def pundit_user { user: Current.user, diff --git a/app/controllers/concerns/request_exception_handler.rb b/app/controllers/concerns/request_exception_handler.rb new file mode 100644 index 000000000..3ce486012 --- /dev/null +++ b/app/controllers/concerns/request_exception_handler.rb @@ -0,0 +1,47 @@ +module RequestExceptionHandler + extend ActiveSupport::Concern + + included do + rescue_from ActiveRecord::RecordInvalid, with: :render_record_invalid + end + + private + + def handle_with_exception + yield + rescue ActiveRecord::RecordNotFound => e + Sentry.capture_exception(e) + render_not_found_error('Resource could not be found') + rescue Pundit::NotAuthorizedError + render_unauthorized('You are not authorized to do this action') + ensure + # to address the thread variable leak issues in Puma/Thin webserver + Current.reset + end + + def render_unauthorized(message) + render json: { error: message }, status: :unauthorized + end + + def render_not_found_error(message) + render json: { error: message }, status: :not_found + end + + def render_could_not_create_error(message) + render json: { error: message }, status: :unprocessable_entity + end + + def render_internal_server_error(message) + render json: { error: message }, status: :internal_server_error + end + + def render_record_invalid(exception) + render json: { + message: exception.record.errors.full_messages.join(', ') + }, status: :unprocessable_entity + end + + def render_error_response(exception) + render json: exception.to_hash, status: exception.http_status + end +end diff --git a/app/controllers/platform/api/v1/users_controller.rb b/app/controllers/platform/api/v1/users_controller.rb index ccec3b2bc..4ee14d0b6 100644 --- a/app/controllers/platform/api/v1/users_controller.rb +++ b/app/controllers/platform/api/v1/users_controller.rb @@ -7,8 +7,8 @@ class Platform::Api::V1::UsersController < PlatformController def create @resource = (User.find_by(email: user_params[:email]) || User.new(user_params)) - @resource.confirm @resource.save! + @resource.confirm @platform_app.platform_app_permissibles.find_or_create_by(permissible: @resource) end diff --git a/app/controllers/platform_controller.rb b/app/controllers/platform_controller.rb index c1ecfc500..335f92483 100644 --- a/app/controllers/platform_controller.rb +++ b/app/controllers/platform_controller.rb @@ -1,4 +1,6 @@ class PlatformController < ActionController::API + include RequestExceptionHandler + before_action :ensure_access_token before_action :set_platform_app before_action :set_resource, only: [:update, :show, :destroy] diff --git a/app/controllers/public_controller.rb b/app/controllers/public_controller.rb index 9e5a7e6ba..b59a4296e 100644 --- a/app/controllers/public_controller.rb +++ b/app/controllers/public_controller.rb @@ -1,5 +1,6 @@ # TODO: we should switch to ActionController::API for the base classes # One of the specs is failing when I tried doing that, lets revisit in future class PublicController < ActionController::Base + include RequestExceptionHandler skip_before_action :verify_authenticity_token end diff --git a/app/javascript/dashboard/api/inboxMembers.js b/app/javascript/dashboard/api/inboxMembers.js index 3716f89ab..64f78845f 100644 --- a/app/javascript/dashboard/api/inboxMembers.js +++ b/app/javascript/dashboard/api/inboxMembers.js @@ -6,8 +6,8 @@ class InboxMembers extends ApiClient { super('inbox_members', { accountScoped: true }); } - create({ inboxId, agentList }) { - return axios.post(this.url, { + update({ inboxId, agentList }) { + return axios.patch(this.url, { inbox_id: inboxId, user_ids: agentList, }); diff --git a/app/javascript/dashboard/store/modules/inboxMembers.js b/app/javascript/dashboard/store/modules/inboxMembers.js index ac0e85983..ff8825e55 100644 --- a/app/javascript/dashboard/store/modules/inboxMembers.js +++ b/app/javascript/dashboard/store/modules/inboxMembers.js @@ -5,7 +5,7 @@ export const actions = { return InboxMembersAPI.show(inboxId); }, create(_, { inboxId, agentList }) { - return InboxMembersAPI.create({ inboxId, agentList }); + return InboxMembersAPI.update({ inboxId, agentList }); }, }; diff --git a/app/models/inbox.rb b/app/models/inbox.rb index 7e4316ffe..9853ce79d 100644 --- a/app/models/inbox.rb +++ b/app/models/inbox.rb @@ -62,7 +62,7 @@ class Inbox < ApplicationRecord end def remove_member(user_id) - member = inbox_members.find_by(user_id: user_id) + member = inbox_members.find_by!(user_id: user_id) member.try(:destroy) end diff --git a/app/views/api/v1/accounts/inbox_members/create.json.jbuilder b/app/views/api/v1/accounts/inbox_members/create.json.jbuilder new file mode 100644 index 000000000..1660ea43d --- /dev/null +++ b/app/views/api/v1/accounts/inbox_members/create.json.jbuilder @@ -0,0 +1,5 @@ +json.payload do + json.array! @agents do |agent| + json.partial! 'api/v1/models/agent.json.jbuilder', resource: agent + end +end diff --git a/app/views/api/v1/accounts/inbox_members/update.json.jbuilder b/app/views/api/v1/accounts/inbox_members/update.json.jbuilder new file mode 100644 index 000000000..1660ea43d --- /dev/null +++ b/app/views/api/v1/accounts/inbox_members/update.json.jbuilder @@ -0,0 +1,5 @@ +json.payload do + json.array! @agents do |agent| + json.partial! 'api/v1/models/agent.json.jbuilder', resource: agent + end +end diff --git a/config/routes.rb b/config/routes.rb index fea3b89b1..d7b8cb276 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -104,7 +104,12 @@ Rails.application.routes.draw do post :set_agent_bot, on: :member delete :avatar, on: :member end - resources :inbox_members, only: [:create, :show], param: :inbox_id + resources :inbox_members, only: [:create, :show], param: :inbox_id do + collection do + delete :destroy + patch :update + end + end resources :labels, only: [:index, :show, :create, :update, :destroy] resources :notifications, only: [:index, :update] do diff --git a/spec/controllers/api/v1/accounts/inbox_members_controller_spec.rb b/spec/controllers/api/v1/accounts/inbox_members_controller_spec.rb index 1361f34b6..0bf5eba5a 100644 --- a/spec/controllers/api/v1/accounts/inbox_members_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/inbox_members_controller_spec.rb @@ -4,82 +4,12 @@ RSpec.describe 'Inbox Member API', type: :request do let(:account) { create(:account) } let(:inbox) { create(:inbox, account: account) } - describe 'POST /api/v1/accounts/{account.id}/inbox_members' do - context 'when it is an unauthenticated user' do - it 'returns unauthorized' do - post "/api/v1/accounts/#{account.id}/inbox_members" - - expect(response).to have_http_status(:unauthorized) - end - end - - context 'when it is an authenticated agent' do - let(:agent) { create(:user, account: account, role: :agent) } - - before do - create(:inbox_member, user: agent, inbox: inbox) - end - - it 'returns unauthorized' do - params = { inbox_id: inbox.id, user_ids: [agent.id] } - - post "/api/v1/accounts/#{account.id}/inbox_members", - headers: agent.create_new_auth_token, - params: params, - as: :json - - expect(response).to have_http_status(:unauthorized) - end - end - - context 'when it is an authenticated user with access to inbox' do - let(:administrator) { create(:user, account: account, role: :administrator) } - let(:agent) { create(:user, account: account, role: :agent) } - - it 'modifies inbox members' do - params = { inbox_id: inbox.id, user_ids: [agent.id] } - - post "/api/v1/accounts/#{account.id}/inbox_members", - headers: administrator.create_new_auth_token, - params: params, - as: :json - - expect(response).to have_http_status(:success) - expect(inbox.inbox_members&.count).to eq(1) - expect(inbox.inbox_members&.first&.user).to eq(agent) - end - - it 'renders not found when inbox not found' do - params = { inbox_id: nil, user_ids: [agent.id] } - - post "/api/v1/accounts/#{account.id}/inbox_members", - headers: administrator.create_new_auth_token, - params: params, - as: :json - - expect(response).to have_http_status(:not_found) - end - - it 'renders error on invalid params' do - params = { inbox_id: inbox.id, user_ids: ['invalid'] } - - post "/api/v1/accounts/#{account.id}/inbox_members", - headers: administrator.create_new_auth_token, - params: params, - as: :json - - expect(response).to have_http_status(:unprocessable_entity) - expect(response.body).to include('Could not add agents to inbox') - end - end - end - describe 'GET /api/v1/accounts/{account.id}/inbox_members/:id' do let(:inbox_member) { create(:inbox_member, inbox: inbox) } context 'when it is an unauthenticated user' do it 'returns unauthorized' do - get "/api/v1/accounts/#{account.id}/inbox_members/#{inbox_member.id}" + get "/api/v1/accounts/#{account.id}/inbox_members/#{inbox.id}" expect(response).to have_http_status(:unauthorized) end @@ -112,4 +42,242 @@ RSpec.describe 'Inbox Member API', type: :request do end end end + + describe 'POST /api/v1/accounts/{account.id}/inbox_members' do + context 'when it is an unauthenticated user' do + it 'returns unauthorized' do + post "/api/v1/accounts/#{account.id}/inbox_members" + + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when it is an authenticated agent' do + let(:agent) { create(:user, account: account, role: :agent) } + + before do + create(:inbox_member, user: agent, inbox: inbox) + end + + it 'returns unauthorized' do + params = { inbox_id: inbox.id, user_ids: [agent.id] } + + post "/api/v1/accounts/#{account.id}/inbox_members", + headers: agent.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when it is an administrator' do + let(:administrator) { create(:user, account: account, role: :administrator) } + let(:old_agent) { create(:user, account: account, role: :agent) } + let(:agent_to_add) { create(:user, account: account, role: :agent) } + + before do + create(:inbox_member, user: old_agent, inbox: inbox) + end + + it 'add inbox members' do + params = { inbox_id: inbox.id, user_ids: [agent_to_add.id] } + + post "/api/v1/accounts/#{account.id}/inbox_members", + headers: administrator.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:success) + expect(inbox.inbox_members&.count).to eq(2) + expect(inbox.inbox_members&.second&.user).to eq(agent_to_add) + end + + it 'renders not found when inbox not found' do + params = { inbox_id: nil, user_ids: [agent_to_add.id] } + + post "/api/v1/accounts/#{account.id}/inbox_members", + headers: administrator.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:not_found) + end + + it 'renders error on invalid params' do + params = { inbox_id: inbox.id, user_ids: ['invalid'] } + + post "/api/v1/accounts/#{account.id}/inbox_members", + headers: administrator.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:unprocessable_entity) + expect(response.body).to include('User must exist') + end + end + end + + describe 'PATCH /api/v1/accounts/{account.id}/inbox_members' do + context 'when it is an unauthenticated user' do + it 'returns unauthorized' do + patch "/api/v1/accounts/#{account.id}/inbox_members" + + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when it is an authenticated agent' do + let(:agent) { create(:user, account: account, role: :agent) } + + before do + create(:inbox_member, user: agent, inbox: inbox) + end + + it 'returns unauthorized' do + params = { inbox_id: inbox.id, user_ids: [agent.id] } + + patch "/api/v1/accounts/#{account.id}/inbox_members", + headers: agent.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when it is an administrator' do + let(:administrator) { create(:user, account: account, role: :administrator) } + let(:old_agent) { create(:user, account: account, role: :agent) } + let(:agent_to_add) { create(:user, account: account, role: :agent) } + + before do + create(:inbox_member, user: old_agent, inbox: inbox) + end + + it 'modifies inbox members' do + params = { inbox_id: inbox.id, user_ids: [agent_to_add.id] } + + patch "/api/v1/accounts/#{account.id}/inbox_members", + headers: administrator.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:success) + expect(inbox.inbox_members&.count).to eq(1) + expect(inbox.inbox_members&.first&.user).to eq(agent_to_add) + end + + it 'renders not found when inbox not found' do + params = { inbox_id: nil, user_ids: [agent_to_add.id] } + + patch "/api/v1/accounts/#{account.id}/inbox_members", + headers: administrator.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:not_found) + end + + it 'renders error on invalid params' do + params = { inbox_id: inbox.id, user_ids: ['invalid'] } + + patch "/api/v1/accounts/#{account.id}/inbox_members", + headers: administrator.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:unprocessable_entity) + expect(response.body).to include('User must exist') + end + end + end + + describe 'DELETE /api/v1/accounts/{account.id}/inbox_members' do + context 'when it is an unauthenticated user' do + it 'returns unauthorized' do + delete "/api/v1/accounts/#{account.id}/inbox_members" + + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when it is an authenticated agent' do + let(:agent) { create(:user, account: account, role: :agent) } + + before do + create(:inbox_member, user: agent, inbox: inbox) + end + + it 'returns unauthorized' do + params = { inbox_id: inbox.id, user_ids: [agent.id] } + + delete "/api/v1/accounts/#{account.id}/inbox_members", + headers: agent.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when it is an administrator' do + let(:administrator) { create(:user, account: account, role: :administrator) } + let(:old_agent) { create(:user, account: account, role: :agent) } + let(:agent_to_delete) { create(:user, account: account, role: :agent) } + let(:non_member_agent) { create(:user, account: account, role: :agent) } + + before do + create(:inbox_member, user: old_agent, inbox: inbox) + create(:inbox_member, user: agent_to_delete, inbox: inbox) + end + + it 'deletes inbox members' do + params = { inbox_id: inbox.id, user_ids: [agent_to_delete.id] } + + delete "/api/v1/accounts/#{account.id}/inbox_members", + headers: administrator.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:success) + expect(inbox.inbox_members&.count).to eq(1) + end + + it 'renders not found when inbox not found' do + params = { inbox_id: nil, user_ids: [agent_to_delete.id] } + + delete "/api/v1/accounts/#{account.id}/inbox_members", + headers: administrator.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:not_found) + end + + it 'renders error on invalid params' do + params = { inbox_id: inbox.id, user_ids: ['invalid'] } + + delete "/api/v1/accounts/#{account.id}/inbox_members", + headers: administrator.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:not_found) + expect(response.body).to include('Resource could not be found') + end + + it 'renders error on non member params' do + params = { inbox_id: inbox.id, user_ids: [non_member_agent.id] } + + delete "/api/v1/accounts/#{account.id}/inbox_members", + headers: administrator.create_new_auth_token, + params: params, + as: :json + + expect(response).to have_http_status(:not_found) + expect(response.body).to include('Resource could not be found') + end + end + end end diff --git a/swagger/definitions/index.yml b/swagger/definitions/index.yml index a2fd247d1..fb24800de 100644 --- a/swagger/definitions/index.yml +++ b/swagger/definitions/index.yml @@ -20,6 +20,8 @@ message: $ref: ./resource/message.yml user: $ref: ./resource/user.yml +agent: + $ref: ./resource/agent.yml inbox: $ref: ./resource/inbox.yml agent_bot: diff --git a/swagger/definitions/resource/agent.yml b/swagger/definitions/resource/agent.yml new file mode 100644 index 000000000..0473d3d87 --- /dev/null +++ b/swagger/definitions/resource/agent.yml @@ -0,0 +1,25 @@ +type: object +properties: + id: + type: number + uid: + type: string + name: + type: string + available_name: + type: string + display_name: + type: string + email: + type: string + account_id: + type: number + role: + type: string + enum: ['agent', 'administrator'] + confirmed: + type: boolean + custom_attributes: + type: object + description: Available for users who are created through platform APIs and has custom attributes associated. + diff --git a/swagger/parameters/inbox_id.yml b/swagger/parameters/inbox_id.yml new file mode 100644 index 000000000..58640fb08 --- /dev/null +++ b/swagger/parameters/inbox_id.yml @@ -0,0 +1,6 @@ +in: path +name: inbox_id +schema: + type: integer +required: true +description: The ID of the Inbox diff --git a/swagger/parameters/index.yml b/swagger/parameters/index.yml index 7d2f196e1..89b685a41 100644 --- a/swagger/parameters/index.yml +++ b/swagger/parameters/index.yml @@ -7,6 +7,9 @@ agent_bot_id: team_id: $ref: ./team_id.yml +inbox_id: + $ref: ./inbox_id.yml + hook_id: $ref: ./hook_id.yml diff --git a/swagger/paths/inboxes/inbox_members/create.yml b/swagger/paths/inboxes/inbox_members/create.yml new file mode 100644 index 000000000..6ffd75af5 --- /dev/null +++ b/swagger/paths/inboxes/inbox_members/create.yml @@ -0,0 +1,36 @@ +tags: + - Inbox +operationId: add-new-agent-to-inbox +summary: Add a New Agent +description: Add a new Agent to Inbox +security: + - userApiKey: [] +parameters: + - name: data + in: body + required: true + schema: + type: object + properties: + inbox_id: + type: string + description: The ID of the inbox + required: true + user_ids: + type: array + description: IDs of users to be added to the inbox + required: true +responses: + 200: + description: Success + schema: + type: array + description: 'Array of all active agents' + items: + $ref: '#/definitions/agent' + 404: + description: Inbox not found + 403: + description: Access denied + 422: + description: User must exist diff --git a/swagger/paths/inboxes/inbox_members/delete.yml b/swagger/paths/inboxes/inbox_members/delete.yml new file mode 100644 index 000000000..a19f1c179 --- /dev/null +++ b/swagger/paths/inboxes/inbox_members/delete.yml @@ -0,0 +1,31 @@ +tags: + - Inbox +operationId: delete-agent-in-inbox +summary: Remove an Agent from Inbox +description: Remove an Agent from Inbox +security: + - userApiKey: [] +parameters: + - name: data + in: body + required: true + schema: + type: object + properties: + inbox_id: + type: string + description: The ID of the inbox + required: true + user_ids: + type: array + description: IDs of users to be deleted from the inbox + required: true +responses: + 200: + description: Success + 404: + description: Inbox not found + 403: + description: Access denied + 422: + description: User must exist diff --git a/swagger/paths/inboxes/inbox_members/show.yml b/swagger/paths/inboxes/inbox_members/show.yml new file mode 100644 index 000000000..af358f78f --- /dev/null +++ b/swagger/paths/inboxes/inbox_members/show.yml @@ -0,0 +1,21 @@ +tags: + - Inbox +operationId: get-inbox-members +summary: List Agents in Inbox +description: Get Details of Agents in an Inbox +security: + - userApiKey: [] +parameters: + - $ref: '#/parameters/inbox_id' +responses: + 200: + description: Success + schema: + type: array + description: 'Array of all active agents' + items: + $ref: '#/definitions/agent' + 404: + description: Inbox not found + 403: + description: Access denied diff --git a/swagger/paths/inboxes/inbox_members/update.yml b/swagger/paths/inboxes/inbox_members/update.yml new file mode 100644 index 000000000..0bcf81747 --- /dev/null +++ b/swagger/paths/inboxes/inbox_members/update.yml @@ -0,0 +1,36 @@ +tags: + - Inbox +operationId: update-agents-in-inbox +summary: Update Agents in Inbox +description: All agents execept the one passed in params will be removed +security: + - userApiKey: [] +parameters: + - name: data + in: body + required: true + schema: + type: object + properties: + inbox_id: + type: string + description: The ID of the inbox + required: true + user_ids: + type: array + description: IDs of users to be added to the inbox + required: true +responses: + 200: + description: Success + schema: + type: array + description: 'Array of all active agents' + items: + $ref: '#/definitions/agent' + 404: + description: Inbox not found + 403: + description: Access denied + 422: + description: User must exist diff --git a/swagger/paths/inboxes/show.yml b/swagger/paths/inboxes/show.yml index 92811190a..a0d44c1d2 100644 --- a/swagger/paths/inboxes/show.yml +++ b/swagger/paths/inboxes/show.yml @@ -1,7 +1,7 @@ get: tags: - Inbox - operationId: GetInboxe + operationId: GetInbox summary: Get an inbox description: Get an inbox available in the current account parameters: diff --git a/swagger/paths/index.yml b/swagger/paths/index.yml index d0388e092..2fb77e254 100644 --- a/swagger/paths/index.yml +++ b/swagger/paths/index.yml @@ -209,6 +209,18 @@ public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversat /api/v1/accounts/{account_id}/inboxes/{id}/set_agent_bot: $ref: ./inboxes/set_agent_bot.yml +# Inbox Members +/api/v1/accounts/{account_id}/inbox_members: + get: + $ref: ./inboxes/inbox_members/show.yml + post: + $ref: ./inboxes/inbox_members/create.yml + patch: + $ref: ./inboxes/inbox_members/update.yml + delete: + $ref: ./inboxes/inbox_members/delete.yml + + # Messages /api/v1/accounts/{account_id}/conversations/{id}/messages: @@ -273,7 +285,7 @@ public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversat ### Custom Filters goes here -# Teams +# Custom Filters /api/v1/accounts/{account_id}/custom_filters: parameters: - $ref: '#/parameters/account_id' diff --git a/swagger/swagger.json b/swagger/swagger.json index 562f9a0f7..d9254d8e5 100644 --- a/swagger/swagger.json +++ b/swagger/swagger.json @@ -1920,7 +1920,7 @@ "tags": [ "Inbox" ], - "operationId": "GetInboxe", + "operationId": "GetInbox", "summary": "Get an inbox", "description": "Get an inbox available in the current account", "parameters": [ @@ -2198,6 +2198,213 @@ } } }, + "/api/v1/accounts/{account_id}/inbox_members": { + "get": { + "tags": [ + "Inbox" + ], + "operationId": "get-inbox-members", + "summary": "List Agents in Inbox", + "description": "Get Details of Agents in an Inbox", + "security": [ + { + "userApiKey": [ + + ] + } + ], + "parameters": [ + { + "$ref": "#/parameters/inbox_id" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "description": "Array of all active agents", + "items": { + "$ref": "#/definitions/agent" + } + } + }, + "404": { + "description": "Inbox not found" + }, + "403": { + "description": "Access denied" + } + } + }, + "post": { + "tags": [ + "Inbox" + ], + "operationId": "add-new-agent-to-inbox", + "summary": "Add a New Agent", + "description": "Add a new Agent to Inbox", + "security": [ + { + "userApiKey": [ + + ] + } + ], + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "inbox_id": { + "type": "string", + "description": "The ID of the inbox", + "required": true + }, + "user_ids": { + "type": "array", + "description": "IDs of users to be added to the inbox", + "required": true + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "description": "Array of all active agents", + "items": { + "$ref": "#/definitions/agent" + } + } + }, + "404": { + "description": "Inbox not found" + }, + "403": { + "description": "Access denied" + }, + "422": { + "description": "User must exist" + } + } + }, + "patch": { + "tags": [ + "Inbox" + ], + "operationId": "update-agents-in-inbox", + "summary": "Update Agents in Inbox", + "description": "All agents execept the one passed in params will be removed", + "security": [ + { + "userApiKey": [ + + ] + } + ], + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "inbox_id": { + "type": "string", + "description": "The ID of the inbox", + "required": true + }, + "user_ids": { + "type": "array", + "description": "IDs of users to be added to the inbox", + "required": true + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "description": "Array of all active agents", + "items": { + "$ref": "#/definitions/agent" + } + } + }, + "404": { + "description": "Inbox not found" + }, + "403": { + "description": "Access denied" + }, + "422": { + "description": "User must exist" + } + } + }, + "delete": { + "tags": [ + "Inbox" + ], + "operationId": "delete-agent-in-inbox", + "summary": "Remove an Agent from Inbox", + "description": "Remove an Agent from Inbox", + "security": [ + { + "userApiKey": [ + + ] + } + ], + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "inbox_id": { + "type": "string", + "description": "The ID of the inbox", + "required": true + }, + "user_ids": { + "type": "array", + "description": "IDs of users to be deleted from the inbox", + "required": true + } + } + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "404": { + "description": "Inbox not found" + }, + "403": { + "description": "Access denied" + }, + "422": { + "description": "User must exist" + } + } + } + }, "/api/v1/accounts/{account_id}/conversations/{id}/messages": { "post": { "tags": [ @@ -3193,6 +3400,46 @@ } } }, + "agent": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "available_name": { + "type": "string" + }, + "display_name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "account_id": { + "type": "number" + }, + "role": { + "type": "string", + "enum": [ + "agent", + "administrator" + ] + }, + "confirmed": { + "type": "boolean" + }, + "custom_attributes": { + "type": "object", + "description": "Available for users who are created through platform APIs and has custom attributes associated." + } + } + }, "inbox": { "type": "object", "properties": { @@ -4128,6 +4375,15 @@ "required": true, "description": "The ID of the team to be updated" }, + "inbox_id": { + "in": "path", + "name": "inbox_id", + "schema": { + "type": "integer" + }, + "required": true, + "description": "The ID of the Inbox" + }, "hook_id": { "in": "path", "name": "hook_id",