chore: Ensure privilege validations for API endpoints (#2224)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
parent
5a95c74bf6
commit
534acfbf96
27 changed files with 335 additions and 119 deletions
|
@ -16,4 +16,8 @@ class Api::BaseController < ApplicationController
|
|||
|
||||
authorize(model)
|
||||
end
|
||||
|
||||
def check_admin_authorization?
|
||||
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,6 +11,7 @@ class Api::V1::Accounts::Contacts::ContactInboxesController < Api::V1::Accounts:
|
|||
|
||||
def ensure_inbox
|
||||
@inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
authorize @inbox, :show?
|
||||
end
|
||||
|
||||
def ensure_contact
|
||||
|
|
|
@ -8,9 +8,7 @@ class Api::V1::Accounts::Contacts::ConversationsController < Api::V1::Accounts::
|
|||
private
|
||||
|
||||
def inbox_ids
|
||||
if Current.user.administrator?
|
||||
Current.account.inboxes.pluck(:id)
|
||||
elsif Current.user.agent?
|
||||
if Current.user.administrator? || Current.user.agent?
|
||||
Current.user.assigned_inboxes.pluck(:id)
|
||||
else
|
||||
[]
|
||||
|
|
|
@ -48,7 +48,8 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
|||
def show; end
|
||||
|
||||
def contactable_inboxes
|
||||
@contactable_inboxes = Contacts::ContactableInboxesService.new(contact: @contact).get
|
||||
@all_contactable_inboxes = Contacts::ContactableInboxesService.new(contact: @contact).get
|
||||
@contactable_inboxes = @all_contactable_inboxes.select { |contactable_inbox| policy(contactable_inbox[:inbox]).show? }
|
||||
end
|
||||
|
||||
def create
|
||||
|
|
|
@ -5,5 +5,6 @@ class Api::V1::Accounts::Conversations::BaseController < Api::V1::Accounts::Base
|
|||
|
||||
def conversation
|
||||
@conversation ||= Current.account.conversations.find_by(display_id: params[:conversation_id])
|
||||
authorize @conversation.inbox, :show?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseController
|
||||
include Events::Types
|
||||
|
||||
before_action :conversation, except: [:index]
|
||||
before_action :conversation, except: [:index, :meta, :search, :create]
|
||||
before_action :contact_inbox, only: [:create]
|
||||
|
||||
def index
|
||||
|
@ -79,21 +79,26 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
|||
end
|
||||
|
||||
def conversation
|
||||
@conversation ||= Current.account.conversations.find_by(display_id: params[:id])
|
||||
@conversation ||= Current.account.conversations.find_by!(display_id: params[:id])
|
||||
authorize @conversation.inbox, :show?
|
||||
end
|
||||
|
||||
def contact_inbox
|
||||
@contact_inbox = build_contact_inbox
|
||||
|
||||
@contact_inbox ||= ::ContactInbox.find_by!(source_id: params[:source_id])
|
||||
authorize @contact_inbox.inbox, :show?
|
||||
end
|
||||
|
||||
def build_contact_inbox
|
||||
return if params[:contact_id].blank? || params[:inbox_id].blank?
|
||||
|
||||
inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
authorize inbox, :show?
|
||||
|
||||
ContactInboxBuilder.new(
|
||||
contact_id: params[:contact_id],
|
||||
inbox_id: params[:inbox_id],
|
||||
inbox_id: inbox.id,
|
||||
source_id: params[:source_id]
|
||||
).perform
|
||||
end
|
||||
|
|
|
@ -3,15 +3,19 @@ class Api::V1::Accounts::InboxMembersController < Api::V1::Accounts::BaseControl
|
|||
before_action :current_agents_ids, only: [:create]
|
||||
|
||||
def create
|
||||
# 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')
|
||||
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')
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
authorize @inbox, :show?
|
||||
@agents = Current.account.users.where(id: @inbox.members.select(:user_id))
|
||||
end
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
|||
|
||||
def fetch_inbox
|
||||
@inbox = Current.account.inboxes.find(params[:id])
|
||||
authorize @inbox, :show?
|
||||
end
|
||||
|
||||
def fetch_agent_bot
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Api::V1::Accounts::Integrations::AppsController < Api::V1::Accounts::BaseController
|
||||
before_action :check_admin_authorization?
|
||||
before_action :fetch_apps, only: [:index]
|
||||
before_action :fetch_app, only: [:show]
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Api::V1::Accounts::Integrations::SlackController < Api::V1::Accounts::BaseController
|
||||
before_action :check_admin_authorization?
|
||||
before_action :fetch_hook, only: [:update, :destroy]
|
||||
|
||||
def create
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
|
||||
before_action :check_authorization
|
||||
|
||||
def account
|
||||
builder = V2::ReportBuilder.new(Current.account, account_report_params)
|
||||
data = builder.build
|
||||
|
@ -23,6 +25,10 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
|
|||
|
||||
private
|
||||
|
||||
def check_authorization
|
||||
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||
end
|
||||
|
||||
def account_summary_params
|
||||
{
|
||||
type: :account,
|
||||
|
|
|
@ -48,15 +48,11 @@ class ConversationFinder
|
|||
private
|
||||
|
||||
def set_inboxes
|
||||
if params[:inbox_id]
|
||||
@inbox_ids = current_account.inboxes.where(id: params[:inbox_id])
|
||||
else
|
||||
if @current_user.administrator?
|
||||
@inbox_ids = current_account.inboxes.pluck(:id)
|
||||
elsif @current_user.agent?
|
||||
@inbox_ids = @current_user.assigned_inboxes.pluck(:id)
|
||||
end
|
||||
end
|
||||
@inbox_ids = if params[:inbox_id]
|
||||
current_account.inboxes.where(id: params[:inbox_id])
|
||||
else
|
||||
@current_user.assigned_inboxes.pluck(:id)
|
||||
end
|
||||
end
|
||||
|
||||
def set_assignee_type
|
||||
|
|
|
@ -122,7 +122,7 @@ class User < ApplicationRecord
|
|||
end
|
||||
|
||||
def assigned_inboxes
|
||||
inboxes.where(account_id: Current.account.id)
|
||||
administrator? ? Current.account.inboxes : inboxes.where(account_id: Current.account.id)
|
||||
end
|
||||
|
||||
def administrator?
|
||||
|
|
5
app/policies/conversation_policy.rb
Normal file
5
app/policies/conversation_policy.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class ConversationPolicy < ApplicationPolicy
|
||||
def index?
|
||||
true
|
||||
end
|
||||
end
|
|
@ -11,11 +11,7 @@ class InboxPolicy < ApplicationPolicy
|
|||
end
|
||||
|
||||
def resolve
|
||||
if @account_user.administrator?
|
||||
scope.all
|
||||
elsif @account_user.agent?
|
||||
user.assigned_inboxes
|
||||
end
|
||||
user.assigned_inboxes
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -23,6 +19,13 @@ class InboxPolicy < ApplicationPolicy
|
|||
true
|
||||
end
|
||||
|
||||
def show?
|
||||
# FIXME: for agent bots, lets bring this validation to policies as well in future
|
||||
return true if @user.blank?
|
||||
|
||||
Current.user.assigned_inboxes.include? record
|
||||
end
|
||||
|
||||
def assignable_agents?
|
||||
true
|
||||
end
|
||||
|
|
|
@ -2,6 +2,8 @@ require 'rails_helper'
|
|||
|
||||
RSpec.describe 'Agents API', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:admin) { create(:user, account: account, role: :administrator) }
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
describe 'GET /api/v1/accounts/{account.id}/agents' do
|
||||
context 'when it is an unauthenticated user' do
|
||||
|
@ -38,7 +40,13 @@ RSpec.describe 'Agents API', type: :request do
|
|||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:admin) { create(:user, account: account, role: :administrator) }
|
||||
it 'returns unauthorized for agents' do
|
||||
delete "/api/v1/accounts/#{account.id}/agents/#{other_agent.id}",
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'deletes an agent' do
|
||||
delete "/api/v1/accounts/#{account.id}/agents/#{other_agent.id}",
|
||||
|
@ -63,10 +71,17 @@ RSpec.describe 'Agents API', type: :request do
|
|||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:admin) { create(:user, account: account, role: :administrator) }
|
||||
|
||||
params = { name: 'TestUser' }
|
||||
|
||||
it 'returns unauthorized for agents' do
|
||||
put "/api/v1/accounts/#{account.id}/agents/#{other_agent.id}",
|
||||
params: params,
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'modifies an agent' do
|
||||
put "/api/v1/accounts/#{account.id}/agents/#{other_agent.id}",
|
||||
params: params,
|
||||
|
@ -91,10 +106,17 @@ RSpec.describe 'Agents API', type: :request do
|
|||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:admin) { create(:user, account: account, role: :administrator) }
|
||||
|
||||
params = { name: 'NewUser', email: Faker::Internet.email, role: :agent }
|
||||
|
||||
it 'returns unauthorized for agents' do
|
||||
post "/api/v1/accounts/#{account.id}/agents",
|
||||
params: params,
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'creates a new agent' do
|
||||
post "/api/v1/accounts/#{account.id}/agents",
|
||||
params: params,
|
||||
|
|
|
@ -5,7 +5,7 @@ RSpec.describe '/api/v1/accounts/{account.id}/contacts/:id/contact_inboxes', typ
|
|||
let(:contact) { create(:contact, account: account) }
|
||||
let(:channel_twilio_sms) { create(:channel_twilio_sms, account: account) }
|
||||
let(:channel_api) { create(:channel_api, account: account) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:agent) { create(:user, account: account) }
|
||||
|
||||
describe 'GET /api/v1/accounts/{account.id}/contacts/:id/contact_inboxes' do
|
||||
context 'when unauthenticated user' do
|
||||
|
@ -15,12 +15,13 @@ RSpec.describe '/api/v1/accounts/{account.id}/contacts/:id/contact_inboxes', typ
|
|||
end
|
||||
end
|
||||
|
||||
context 'when user is logged in' do
|
||||
context 'when authenticated user with access to inbox' do
|
||||
it 'creates a contact inbox' do
|
||||
create(:inbox_member, inbox: channel_api.inbox, user: agent)
|
||||
expect do
|
||||
post "/api/v1/accounts/#{account.id}/contacts/#{contact.id}/contact_inboxes",
|
||||
params: { inbox_id: channel_api.inbox.id },
|
||||
headers: user.create_new_auth_token,
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
end.to change(ContactInbox, :count).by(1)
|
||||
|
||||
|
@ -29,10 +30,11 @@ RSpec.describe '/api/v1/accounts/{account.id}/contacts/:id/contact_inboxes', typ
|
|||
end
|
||||
|
||||
it 'throws error for invalid source id' do
|
||||
create(:inbox_member, inbox: channel_twilio_sms.inbox, user: agent)
|
||||
expect do
|
||||
post "/api/v1/accounts/#{account.id}/contacts/#{contact.id}/contact_inboxes",
|
||||
params: { inbox_id: channel_twilio_sms.inbox.id },
|
||||
headers: user.create_new_auth_token,
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
end.to change(ContactInbox, :count).by(0)
|
||||
|
||||
|
|
|
@ -201,18 +201,29 @@ RSpec.describe 'Contacts API', type: :request do
|
|||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:admin) { create(:user, account: account, role: :administrator) }
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
let!(:twilio_sms) { create(:channel_twilio_sms, account: account) }
|
||||
let!(:twilio_sms_inbox) { create(:inbox, channel: twilio_sms, account: account) }
|
||||
let!(:twilio_whatsapp) { create(:channel_twilio_sms, medium: :whatsapp, account: account) }
|
||||
let!(:twilio_whatsapp_inbox) { create(:inbox, channel: twilio_whatsapp, account: account) }
|
||||
|
||||
it 'shows the contactable inboxes which the user has access to' do
|
||||
create(:inbox_member, user: agent, inbox: twilio_whatsapp_inbox)
|
||||
|
||||
it 'shows the contact' do
|
||||
inbox_service = double
|
||||
allow(Contacts::ContactableInboxesService).to receive(:new).and_return(inbox_service)
|
||||
allow(inbox_service).to receive(:get).and_return({})
|
||||
expect(inbox_service).to receive(:get).and_return({})
|
||||
allow(inbox_service).to receive(:get).and_return([
|
||||
{ source_id: '1123', inbox: twilio_sms_inbox },
|
||||
{ source_id: '1123', inbox: twilio_whatsapp_inbox }
|
||||
])
|
||||
expect(inbox_service).to receive(:get)
|
||||
get "/api/v1/accounts/#{account.id}/contacts/#{contact.id}/contactable_inboxes",
|
||||
headers: admin.create_new_auth_token,
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
# only the inboxes which agent has access to are shown
|
||||
expect(JSON.parse(response.body)['payload'].pluck('inbox').pluck('id')).to eq([twilio_whatsapp_inbox.id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,10 +14,14 @@ RSpec.describe 'Conversation Assignment API', type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
context 'when it is an authenticated user with access to the inbox' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
let(:team) { create(:team, account: account) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, inbox: conversation.inbox, user: agent)
|
||||
end
|
||||
|
||||
it 'assigns a user to the conversation' do
|
||||
params = { assignee_id: agent.id }
|
||||
|
||||
|
@ -48,6 +52,7 @@ RSpec.describe 'Conversation Assignment API', type: :request do
|
|||
|
||||
before do
|
||||
conversation.update!(assignee: agent)
|
||||
create(:inbox_member, inbox: conversation.inbox, user: agent)
|
||||
end
|
||||
|
||||
it 'unassigns the assignee from the conversation' do
|
||||
|
@ -69,6 +74,7 @@ RSpec.describe 'Conversation Assignment API', type: :request do
|
|||
|
||||
before do
|
||||
conversation.update!(team: team)
|
||||
create(:inbox_member, inbox: conversation.inbox, user: agent)
|
||||
end
|
||||
|
||||
it 'unassigns the team from the conversation' do
|
||||
|
|
|
@ -17,9 +17,13 @@ RSpec.describe 'Conversation Label API', type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
context 'when it is an authenticated user with access to the conversation' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, inbox: conversation.inbox, user: agent)
|
||||
end
|
||||
|
||||
it 'returns all the labels for the conversation' do
|
||||
get api_v1_account_conversation_labels_url(account_id: account.id, conversation_id: conversation.display_id),
|
||||
headers: agent.create_new_auth_token,
|
||||
|
@ -49,9 +53,14 @@ RSpec.describe 'Conversation Label API', type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
context 'when it is an authenticated user with access to the conversation' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
before do
|
||||
conversation.update_labels('label1, label2')
|
||||
create(:inbox_member, inbox: conversation.inbox, user: agent)
|
||||
end
|
||||
|
||||
it 'creates labels for the conversation' do
|
||||
post api_v1_account_conversation_labels_url(account_id: account.id, conversation_id: conversation.display_id),
|
||||
params: { labels: %w[label3 label4] },
|
||||
|
|
|
@ -15,9 +15,13 @@ RSpec.describe 'Conversation Messages API', type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
context 'when it is an authenticated user with access to conversation' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, inbox: conversation.inbox, user: agent)
|
||||
end
|
||||
|
||||
it 'creates a new outgoing message' do
|
||||
params = { content: 'test-message', private: true }
|
||||
|
||||
|
@ -124,9 +128,13 @@ RSpec.describe 'Conversation Messages API', type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
context 'when it is an authenticated user with access to conversation' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, inbox: conversation.inbox, user: agent)
|
||||
end
|
||||
|
||||
it 'shows the conversation' do
|
||||
get "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/messages",
|
||||
headers: agent.create_new_auth_token,
|
||||
|
@ -149,9 +157,13 @@ RSpec.describe 'Conversation Messages API', type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
context 'when it is an authenticated user with access to conversation' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, inbox: conversation.inbox, user: agent)
|
||||
end
|
||||
|
||||
it 'deletes the message' do
|
||||
delete "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/messages/#{message.id}",
|
||||
headers: agent.create_new_auth_token,
|
||||
|
@ -166,6 +178,10 @@ RSpec.describe 'Conversation Messages API', type: :request do
|
|||
context 'when the message id is invalid' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, inbox: conversation.inbox, user: agent)
|
||||
end
|
||||
|
||||
it 'returns not found error' do
|
||||
delete "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/messages/99999",
|
||||
headers: agent.create_new_auth_token,
|
||||
|
|
|
@ -119,8 +119,27 @@ RSpec.describe 'Conversations API', type: :request do
|
|||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
let(:administrator) { create(:user, account: account, role: :administrator) }
|
||||
|
||||
it 'shows the conversation' do
|
||||
it 'does not shows the conversation if you do not have access to it' do
|
||||
get "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}",
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'shows the conversation if you are an administrator' do
|
||||
get "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}",
|
||||
headers: administrator.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(JSON.parse(response.body, symbolize_names: true)[:id]).to eq(conversation.display_id)
|
||||
end
|
||||
|
||||
it 'shows the conversation if you are an agent with access to inbox' do
|
||||
create(:inbox_member, user: agent, inbox: conversation.inbox)
|
||||
get "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}",
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
@ -149,57 +168,71 @@ RSpec.describe 'Conversations API', type: :request do
|
|||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
it 'creates a new conversation' do
|
||||
it 'will not create a new conversation if agent does not have access to inbox' do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
additional_attributes = { test: 'test' }
|
||||
post "/api/v1/accounts/#{account.id}/conversations",
|
||||
headers: agent.create_new_auth_token,
|
||||
params: { source_id: contact_inbox.source_id, additional_attributes: additional_attributes },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(response_data[:additional_attributes]).to eq(additional_attributes)
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'creates a conversation in specificed status' do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
post "/api/v1/accounts/#{account.id}/conversations",
|
||||
headers: agent.create_new_auth_token,
|
||||
params: { source_id: contact_inbox.source_id, status: 'bot' },
|
||||
as: :json
|
||||
context 'when it is an authenticated user who has access to the inbox' do
|
||||
before do
|
||||
create(:inbox_member, user: agent, inbox: inbox)
|
||||
end
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(response_data[:status]).to eq('bot')
|
||||
end
|
||||
it 'creates a new conversation' do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
additional_attributes = { test: 'test' }
|
||||
post "/api/v1/accounts/#{account.id}/conversations",
|
||||
headers: agent.create_new_auth_token,
|
||||
params: { source_id: contact_inbox.source_id, additional_attributes: additional_attributes },
|
||||
as: :json
|
||||
|
||||
it 'creates a new conversation with message when message is passed' do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
post "/api/v1/accounts/#{account.id}/conversations",
|
||||
headers: agent.create_new_auth_token,
|
||||
params: { source_id: contact_inbox.source_id, message: { content: 'hi' } },
|
||||
as: :json
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(response_data[:additional_attributes]).to eq(additional_attributes)
|
||||
end
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(response_data[:additional_attributes]).to eq({})
|
||||
expect(account.conversations.find_by(display_id: response_data[:id]).messages.first.content).to eq 'hi'
|
||||
end
|
||||
it 'creates a conversation in specificed status' do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
post "/api/v1/accounts/#{account.id}/conversations",
|
||||
headers: agent.create_new_auth_token,
|
||||
params: { source_id: contact_inbox.source_id, status: 'bot' },
|
||||
as: :json
|
||||
|
||||
it 'calls contact inbox builder if contact_id and inbox_id is present' do
|
||||
builder = double
|
||||
contact = create(:contact, account: account)
|
||||
inbox = create(:inbox, account: account)
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
allow(ContactInboxBuilder).to receive(:new).and_return(builder)
|
||||
allow(builder).to receive(:perform)
|
||||
expect(builder).to receive(:perform)
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(response_data[:status]).to eq('bot')
|
||||
end
|
||||
|
||||
post "/api/v1/accounts/#{account.id}/conversations",
|
||||
headers: agent.create_new_auth_token,
|
||||
params: { contact_id: contact.id, inbox_id: inbox.id },
|
||||
as: :json
|
||||
it 'creates a new conversation with message when message is passed' do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
post "/api/v1/accounts/#{account.id}/conversations",
|
||||
headers: agent.create_new_auth_token,
|
||||
params: { source_id: contact_inbox.source_id, message: { content: 'hi' } },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(response_data[:additional_attributes]).to eq({})
|
||||
expect(account.conversations.find_by(display_id: response_data[:id]).messages.outgoing.first.content).to eq 'hi'
|
||||
end
|
||||
|
||||
it 'calls contact inbox builder if contact_id and inbox_id is present' do
|
||||
builder = double
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
allow(ContactInboxBuilder).to receive(:new).and_return(builder)
|
||||
allow(builder).to receive(:perform)
|
||||
expect(builder).to receive(:perform)
|
||||
|
||||
post "/api/v1/accounts/#{account.id}/conversations",
|
||||
headers: agent.create_new_auth_token,
|
||||
params: { contact_id: contact.id, inbox_id: inbox.id },
|
||||
as: :json
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -218,6 +251,10 @@ RSpec.describe 'Conversations API', type: :request do
|
|||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, user: agent, inbox: conversation.inbox)
|
||||
end
|
||||
|
||||
it 'toggles the conversation status' do
|
||||
expect(conversation.status).to eq('open')
|
||||
|
||||
|
@ -268,6 +305,10 @@ RSpec.describe 'Conversations API', type: :request do
|
|||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, user: agent, inbox: conversation.inbox)
|
||||
end
|
||||
|
||||
it 'toggles the conversation status' do
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/toggle_typing_status",
|
||||
|
@ -296,6 +337,10 @@ RSpec.describe 'Conversations API', type: :request do
|
|||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, user: agent, inbox: conversation.inbox)
|
||||
end
|
||||
|
||||
it 'updates last seen' do
|
||||
post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/update_last_seen",
|
||||
headers: agent.create_new_auth_token,
|
||||
|
@ -321,6 +366,10 @@ RSpec.describe 'Conversations API', type: :request do
|
|||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, user: agent, inbox: conversation.inbox)
|
||||
end
|
||||
|
||||
it 'mutes conversation' do
|
||||
post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/mute",
|
||||
headers: agent.create_new_auth_token,
|
||||
|
@ -347,6 +396,10 @@ RSpec.describe 'Conversations API', type: :request do
|
|||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, user: agent, inbox: conversation.inbox)
|
||||
end
|
||||
|
||||
it 'unmutes conversation' do
|
||||
post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/unmute",
|
||||
headers: agent.create_new_auth_token,
|
||||
|
@ -373,6 +426,10 @@ RSpec.describe 'Conversations API', type: :request do
|
|||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
let(:params) { { email: 'test@test.com' } }
|
||||
|
||||
before do
|
||||
create(:inbox_member, user: agent, inbox: conversation.inbox)
|
||||
end
|
||||
|
||||
it 'mutes conversation' do
|
||||
mailer = double
|
||||
allow(ConversationReplyMailer).to receive(:with).and_return(mailer)
|
||||
|
|
|
@ -13,14 +13,34 @@ RSpec.describe 'Inbox Member API', type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
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: agent.create_new_auth_token,
|
||||
headers: administrator.create_new_auth_token,
|
||||
params: params,
|
||||
as: :json
|
||||
|
||||
|
@ -33,7 +53,7 @@ RSpec.describe 'Inbox Member API', type: :request do
|
|||
params = { inbox_id: nil, user_ids: [agent.id] }
|
||||
|
||||
post "/api/v1/accounts/#{account.id}/inbox_members",
|
||||
headers: agent.create_new_auth_token,
|
||||
headers: administrator.create_new_auth_token,
|
||||
params: params,
|
||||
as: :json
|
||||
|
||||
|
@ -44,7 +64,7 @@ RSpec.describe 'Inbox Member API', type: :request do
|
|||
params = { inbox_id: inbox.id, user_ids: ['invalid'] }
|
||||
|
||||
post "/api/v1/accounts/#{account.id}/inbox_members",
|
||||
headers: agent.create_new_auth_token,
|
||||
headers: administrator.create_new_auth_token,
|
||||
params: params,
|
||||
as: :json
|
||||
|
||||
|
@ -65,16 +85,30 @@ RSpec.describe 'Inbox Member API', type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
context 'when it is an authenticated user with out access to inbox' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
it 'returns inbox member' do
|
||||
get "/api/v1/accounts/#{account.id}/inbox_members/#{inbox.id}",
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user with access to inbox' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
it 'returns inbox member' do
|
||||
create(:inbox_member, user: agent, inbox: inbox)
|
||||
|
||||
get "/api/v1/accounts/#{account.id}/inbox_members/#{inbox.id}",
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(JSON.parse(response.body)).to eq({ payload: inbox.inbox_members }.as_json)
|
||||
expect(JSON.parse(response.body)['payload'].pluck('id')).to eq(inbox.inbox_members.pluck(:user_id))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -267,6 +267,10 @@ RSpec.describe 'Inboxes API', type: :request do
|
|||
describe 'GET /api/v1/accounts/{account.id}/inboxes/{inbox.id}/agent_bot' do
|
||||
let(:inbox) { create(:inbox, account: account) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, user: agent, inbox: inbox)
|
||||
end
|
||||
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/agent_bot"
|
||||
|
|
|
@ -12,7 +12,7 @@ RSpec.describe 'Integration Apps API', type: :request do
|
|||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
let(:agent) { create(:user, account: account, role: :administrator) }
|
||||
|
||||
it 'returns all active apps' do
|
||||
first_app = Integrations::App.all.find(&:active?)
|
||||
|
@ -52,7 +52,7 @@ RSpec.describe 'Integration Apps API', type: :request do
|
|||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
let(:agent) { create(:user, account: account, role: :administrator) }
|
||||
|
||||
it 'returns details of the app' do
|
||||
get api_v1_account_integrations_app_url(account_id: account.id, id: 'slack'),
|
||||
|
|
|
@ -2,6 +2,8 @@ require 'rails_helper'
|
|||
|
||||
RSpec.describe 'Reports API', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:admin) { create(:user, account: account, role: :administrator) }
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
let!(:user) { create(:user, account: account) }
|
||||
let!(:inbox) { create(:inbox, account: account) }
|
||||
let(:inbox_member) { create(:inbox_member, user: user, inbox: inbox) }
|
||||
|
@ -21,21 +23,28 @@ RSpec.describe 'Reports API', type: :request do
|
|||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
it 'return timeseries metrics' do
|
||||
params = {
|
||||
metric: 'conversations_count',
|
||||
type: :account,
|
||||
since: Time.zone.today.to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
params = {
|
||||
metric: 'conversations_count',
|
||||
type: :account,
|
||||
since: Time.zone.today.to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
it 'returns unauthorized for agents' do
|
||||
get "/api/v2/accounts/#{account.id}/reports/account",
|
||||
params: params,
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'return timeseries metrics' do
|
||||
get "/api/v2/accounts/#{account.id}/reports/account",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = JSON.parse(response.body)
|
||||
|
||||
|
@ -56,20 +65,27 @@ RSpec.describe 'Reports API', type: :request do
|
|||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
it 'returns summary metrics' do
|
||||
params = {
|
||||
type: :account,
|
||||
since: Time.zone.today.to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
params = {
|
||||
type: :account,
|
||||
since: Time.zone.today.to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
it 'returns unauthorized for agents' do
|
||||
get "/api/v2/accounts/#{account.id}/reports/account_summary",
|
||||
params: params,
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns summary metrics' do
|
||||
get "/api/v2/accounts/#{account.id}/reports/account_summary",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = JSON.parse(response.body)
|
||||
|
||||
|
@ -88,18 +104,24 @@ RSpec.describe 'Reports API', type: :request do
|
|||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
params = {
|
||||
since: 30.days.ago.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
it 'returns summary' do
|
||||
it 'returns unauthorized for agents' do
|
||||
get "/api/v2/accounts/#{account.id}/reports/agents.csv",
|
||||
params: params,
|
||||
headers: agent.create_new_auth_token
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns summary' do
|
||||
get "/api/v2/accounts/#{account.id}/reports/agents.csv",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
@ -115,18 +137,24 @@ RSpec.describe 'Reports API', type: :request do
|
|||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
params = {
|
||||
since: 30.days.ago.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
it 'returns summary' do
|
||||
it 'returns unauthorized for agents' do
|
||||
get "/api/v2/accounts/#{account.id}/reports/inboxes",
|
||||
params: params,
|
||||
headers: agent.create_new_auth_token
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns summary' do
|
||||
get "/api/v2/accounts/#{account.id}/reports/inboxes",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ require 'rails_helper'
|
|||
|
||||
RSpec.describe 'Api::V1::Accounts::Integrations::Slacks', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
let(:agent) { create(:user, account: account, role: :administrator) }
|
||||
let!(:hook) { create(:integrations_hook, account: account) }
|
||||
|
||||
describe 'POST /api/v1/accounts/{account.id}/integrations/slack' do
|
||||
|
|
Loading…
Reference in a new issue