diff --git a/app/controllers/api/v1/accounts/assignable_agents_controller.rb b/app/controllers/api/v1/accounts/assignable_agents_controller.rb new file mode 100644 index 000000000..a712342dd --- /dev/null +++ b/app/controllers/api/v1/accounts/assignable_agents_controller.rb @@ -0,0 +1,24 @@ +class Api::V1::Accounts::AssignableAgentsController < Api::V1::Accounts::BaseController + before_action :fetch_inboxes + + def index + agent_ids = @inboxes.map do |inbox| + authorize inbox, :show? + member_ids = inbox.members.pluck(:user_id) + member_ids + end + agent_ids = agent_ids.inject(:&) + agents = Current.account.users.where(id: agent_ids) + @assignable_agents = (agents + Current.account.administrators).uniq + end + + private + + def fetch_inboxes + @inboxes = Current.account.inboxes.find(permitted_params[:inbox_ids]) + end + + def permitted_params + params.permit(inbox_ids: []) + end +end diff --git a/app/controllers/api/v1/accounts/inboxes_controller.rb b/app/controllers/api/v1/accounts/inboxes_controller.rb index 66a71985d..4bc85546a 100644 --- a/app/controllers/api/v1/accounts/inboxes_controller.rb +++ b/app/controllers/api/v1/accounts/inboxes_controller.rb @@ -12,6 +12,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController def show; end + # Deprecated: This API will be removed in 2.7.0 def assignable_agents @assignable_agents = (Current.account.users.where(id: @inbox.members.select(:user_id)) + Current.account.administrators).uniq end diff --git a/app/javascript/dashboard/api/assignableAgents.js b/app/javascript/dashboard/api/assignableAgents.js new file mode 100644 index 000000000..5b999facf --- /dev/null +++ b/app/javascript/dashboard/api/assignableAgents.js @@ -0,0 +1,16 @@ +/* global axios */ +import ApiClient from './ApiClient'; + +class AssignableAgents extends ApiClient { + constructor() { + super('assignable_agents', { accountScoped: true }); + } + + get(inboxIds) { + return axios.get(this.url, { + params: { inbox_ids: inboxIds }, + }); + } +} + +export default new AssignableAgents(); diff --git a/app/javascript/dashboard/api/inboxes.js b/app/javascript/dashboard/api/inboxes.js index 1cf6ba113..a76ef1414 100644 --- a/app/javascript/dashboard/api/inboxes.js +++ b/app/javascript/dashboard/api/inboxes.js @@ -6,10 +6,6 @@ class Inboxes extends ApiClient { super('inboxes', { accountScoped: true }); } - getAssignableAgents(inboxId) { - return axios.get(`${this.url}/${inboxId}/assignable_agents`); - } - getCampaigns(inboxId) { return axios.get(`${this.url}/${inboxId}/campaigns`); } diff --git a/app/javascript/dashboard/api/specs/assignableAgents.spec.js b/app/javascript/dashboard/api/specs/assignableAgents.spec.js new file mode 100644 index 000000000..6c9c5ec9a --- /dev/null +++ b/app/javascript/dashboard/api/specs/assignableAgents.spec.js @@ -0,0 +1,18 @@ +import assignableAgentsAPI from '../assignableAgents'; +import describeWithAPIMock from './apiSpecHelper'; + +describe('#AssignableAgentsAPI', () => { + describeWithAPIMock('API calls', context => { + it('#getAssignableAgents', () => { + assignableAgentsAPI.get([1]); + expect(context.axiosMock.get).toHaveBeenCalledWith( + '/api/v1/assignable_agents', + { + params: { + inbox_ids: [1], + }, + } + ); + }); + }); +}); diff --git a/app/javascript/dashboard/api/specs/inboxes.spec.js b/app/javascript/dashboard/api/specs/inboxes.spec.js index b261bb930..0d755d44a 100644 --- a/app/javascript/dashboard/api/specs/inboxes.spec.js +++ b/app/javascript/dashboard/api/specs/inboxes.spec.js @@ -10,17 +10,9 @@ describe('#InboxesAPI', () => { expect(inboxesAPI).toHaveProperty('create'); expect(inboxesAPI).toHaveProperty('update'); expect(inboxesAPI).toHaveProperty('delete'); - expect(inboxesAPI).toHaveProperty('getAssignableAgents'); expect(inboxesAPI).toHaveProperty('getCampaigns'); }); describeWithAPIMock('API calls', context => { - it('#getAssignableAgents', () => { - inboxesAPI.getAssignableAgents(1); - expect(context.axiosMock.get).toHaveBeenCalledWith( - '/api/v1/inboxes/1/assignable_agents' - ); - }); - it('#getCampaigns', () => { inboxesAPI.getCampaigns(2); expect(context.axiosMock.get).toHaveBeenCalledWith( diff --git a/app/javascript/dashboard/store/modules/inboxAssignableAgents.js b/app/javascript/dashboard/store/modules/inboxAssignableAgents.js index 31a2d98d0..1acb6897a 100644 --- a/app/javascript/dashboard/store/modules/inboxAssignableAgents.js +++ b/app/javascript/dashboard/store/modules/inboxAssignableAgents.js @@ -1,6 +1,6 @@ import Vue from 'vue'; -import InboxesAPI from 'dashboard/api/inboxes.js'; +import AssignableAgentsAPI from '../../api/assignableAgents'; const state = { records: {}, @@ -31,7 +31,7 @@ export const actions = { try { const { data: { payload }, - } = await InboxesAPI.getAssignableAgents(inboxId); + } = await AssignableAgentsAPI.get([inboxId]); commit(types.SET_INBOX_ASSIGNABLE_AGENTS, { inboxId, members: payload }); } catch (error) { throw new Error(error); diff --git a/app/views/api/v1/accounts/assignable_agents/index.json.jbuilder b/app/views/api/v1/accounts/assignable_agents/index.json.jbuilder new file mode 100644 index 000000000..af71dea1e --- /dev/null +++ b/app/views/api/v1/accounts/assignable_agents/index.json.jbuilder @@ -0,0 +1,5 @@ +json.payload do + json.array! @assignable_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 a80f6ca39..b2029a739 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -43,7 +43,7 @@ Rails.application.routes.draw do resource :bulk_actions, only: [:create] resources :agents, only: [:index, :create, :update, :destroy] resources :agent_bots, only: [:index, :create, :show, :update, :destroy] - + resources :assignable_agents, only: [:index] resources :callbacks, only: [] do collection do post :register_facebook_page diff --git a/spec/controllers/api/v1/accounts/assignable_agents_controller_spec.rb b/spec/controllers/api/v1/accounts/assignable_agents_controller_spec.rb new file mode 100644 index 000000000..6f1a068ee --- /dev/null +++ b/spec/controllers/api/v1/accounts/assignable_agents_controller_spec.rb @@ -0,0 +1,67 @@ +require 'rails_helper' + +RSpec.describe 'Assignable Agents API', type: :request do + let(:account) { create(:account) } + let(:agent1) { create(:user, account: account, role: :agent) } + let!(:agent2) { create(:user, account: account, role: :agent) } + let!(:admin) { create(:user, account: account, role: :administrator) } + + describe 'GET /api/v1/accounts/{account.id}/assignable_agents' do + let(:inbox1) { create(:inbox, account: account) } + let(:inbox2) { create(:inbox, account: account) } + + before do + create(:inbox_member, user: agent1, inbox: inbox1) + create(:inbox_member, user: agent1, inbox: inbox2) + end + + context 'when it is an unauthenticated user' do + it 'returns unauthorized' do + get "/api/v1/accounts/#{account.id}/assignable_agents" + + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when the user is not part of an inbox' do + context 'when the user is an admininstrator' do + it 'returns all assignable inbox members along with administrators' do + get "/api/v1/accounts/#{account.id}/assignable_agents", + params: { inbox_ids: [inbox1.id, inbox2.id] }, + headers: admin.create_new_auth_token, + as: :json + + expect(response).to have_http_status(:success) + response_data = JSON.parse(response.body, symbolize_names: true)[:payload] + expect(response_data.size).to eq(2) + expect(response_data.pluck(:role)).to include('agent', 'administrator') + end + end + + context 'when the user is an agent' do + it 'returns unauthorized' do + get "/api/v1/accounts/#{account.id}/assignable_agents", + params: { inbox_ids: [inbox1.id, inbox2.id] }, + headers: agent2.create_new_auth_token, + as: :json + + expect(response).to have_http_status(:unauthorized) + end + end + end + + context 'when the user is part of the inbox' do + it 'returns all assignable inbox members along with administrators' do + get "/api/v1/accounts/#{account.id}/assignable_agents", + params: { inbox_ids: [inbox1.id, inbox2.id] }, + headers: agent1.create_new_auth_token, + as: :json + + expect(response).to have_http_status(:success) + response_data = JSON.parse(response.body, symbolize_names: true)[:payload] + expect(response_data.size).to eq(2) + expect(response_data.pluck(:role)).to include('agent', 'administrator') + end + end + end +end