Restrict the WhatsApp reauthorization flag to channels whose
provider_config source is 'embedded_signup'. Previously the view exposed
resource.channel.reauthorization_required? for all WhatsApp channels;
now it only returns true when (provider_config || {}).to_h['source'] ==
'embedded_signup' && resource.channel.reauthorization_required?. This
prevents showing reauthorization prompts for manual/API-key flows
(non-OAuth) and safely handles nil provider_config.
# Pull Request Template
## Description
Please include a summary of the change and issue(s) fixed. Also, mention
relevant motivation, context, and any dependencies that this change
requires.
Fixes #13553
## Type of change
Please delete options that are not relevant.
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update
## How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com>
1281 lines
51 KiB
Ruby
1281 lines
51 KiB
Ruby
require 'rails_helper'
|
|
|
|
RSpec.describe 'Inboxes API', type: :request do
|
|
include ActiveJob::TestHelper
|
|
|
|
let(:account) { create(:account) }
|
|
let(:agent) { create(:user, account: account, role: :agent) }
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
|
|
describe 'GET /api/v1/accounts/{account.id}/inboxes' do
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:agent) { create(:user, account: account, role: :agent) }
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
before do
|
|
create(:inbox, account: account)
|
|
create(:inbox_member, user: agent, inbox: inbox)
|
|
end
|
|
|
|
it 'returns all inboxes of current_account as administrator' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response).to conform_schema(200)
|
|
expect(JSON.parse(response.body, symbolize_names: true)[:payload].size).to eq(2)
|
|
end
|
|
|
|
it 'returns only assigned inboxes of current_account as agent' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(JSON.parse(response.body, symbolize_names: true)[:payload].size).to eq(1)
|
|
end
|
|
|
|
context 'when provider_config' do
|
|
let(:inbox) { create(:channel_whatsapp, account: account, sync_templates: false, validate_provider_config: false).inbox }
|
|
|
|
it 'returns provider config attributes for admin' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
expect(response.body).to include('provider_config')
|
|
end
|
|
|
|
it 'will not return provider config for agent' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response.body).not_to include('provider_config')
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v1/accounts/{account.id}/inboxes/{inbox.id}' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:agent) { create(:user, account: account, role: :agent) }
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
it 'returns unauthorized for an agent who is not assigned' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'returns the inbox if administrator' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response).to conform_schema(200)
|
|
expect(JSON.parse(response.body, symbolize_names: true)[:id]).to eq(inbox.id)
|
|
end
|
|
|
|
it 'returns reauthorization_required for embedded signup whatsapp channel when reauth required' do
|
|
whatsapp_channel = create(:channel_whatsapp, account: account, provider: 'whatsapp_cloud', sync_templates: false,
|
|
validate_provider_config: false)
|
|
whatsapp_inbox = create(:inbox, channel: whatsapp_channel, account: account)
|
|
whatsapp_channel.prompt_reauthorization!
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response.parsed_body['reauthorization_required']).to be(true)
|
|
end
|
|
|
|
it 'does not flag reauthorization_required for manual whatsapp channel even when reauth required' do
|
|
whatsapp_channel = create(:channel_whatsapp, account: account, provider: 'whatsapp_cloud', sync_templates: false,
|
|
validate_provider_config: false)
|
|
whatsapp_channel.update!(provider_config: whatsapp_channel.provider_config.merge('source' => 'manual'))
|
|
whatsapp_inbox = create(:inbox, channel: whatsapp_channel, account: account)
|
|
whatsapp_channel.prompt_reauthorization!
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response.parsed_body['reauthorization_required']).to be(false)
|
|
end
|
|
|
|
it 'returns the inbox if assigned inbox is assigned as agent' do
|
|
create(:inbox_member, user: agent, inbox: inbox)
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
expect(data[:id]).to eq(inbox.id)
|
|
expect(data[:hmac_token]).to be_nil
|
|
end
|
|
|
|
it 'returns empty imap details in inbox when agent' do
|
|
email_channel = create(:channel_email, account: account, imap_enabled: true, imap_login: 'test@test.com')
|
|
email_inbox = create(:inbox, channel: email_channel, account: account)
|
|
create(:inbox_member, user: agent, inbox: email_inbox)
|
|
|
|
imap_connection = double
|
|
allow(Mail).to receive(:connection).and_return(imap_connection)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
|
|
expect(data[:imap_enabled]).to be_nil
|
|
expect(data[:imap_login]).to be_nil
|
|
end
|
|
|
|
it 'returns imap details in inbox when admin' do
|
|
email_channel = create(:channel_email, account: account, imap_enabled: true, imap_login: 'test@test.com')
|
|
email_inbox = create(:inbox, channel: email_channel, account: account)
|
|
|
|
imap_connection = double
|
|
allow(Mail).to receive(:connection).and_return(imap_connection)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
|
|
expect(data[:imap_enabled]).to be_truthy
|
|
expect(data[:imap_login]).to eq('test@test.com')
|
|
end
|
|
|
|
context 'when it is a Twilio inbox' do
|
|
let(:twilio_channel) { create(:channel_twilio_sms, account: account, account_sid: 'AC123', auth_token: 'secrettoken') }
|
|
let(:twilio_inbox) { create(:inbox, channel: twilio_channel, account: account) }
|
|
|
|
it 'returns auth_token and account_sid for admin' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{twilio_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
expect(response).to have_http_status(:success)
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
expect(data[:auth_token]).to eq('secrettoken')
|
|
expect(data[:account_sid]).to eq('AC123')
|
|
end
|
|
|
|
it "doesn't return auth_token and account_sid for agent" do
|
|
create(:inbox_member, user: agent, inbox: twilio_inbox)
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{twilio_inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
expect(response).to have_http_status(:success)
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
expect(data[:auth_token]).to be_nil
|
|
expect(data[:account_sid]).to be_nil
|
|
end
|
|
end
|
|
|
|
it 'fetch API inbox without hmac token when agent' do
|
|
api_channel = create(:channel_api, account: account)
|
|
api_inbox = create(:inbox, channel: api_channel, account: account)
|
|
create(:inbox_member, user: agent, inbox: api_inbox)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{api_inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
|
|
expect(data[:hmac_token]).to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v1/accounts/{account.id}/inboxes/{inbox.id}/assignable_agents' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignable_agents"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
before do
|
|
create(:inbox_member, user: agent, inbox: inbox)
|
|
end
|
|
|
|
it 'returns all assignable inbox members along with administrators' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/assignable_agents",
|
|
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
|
|
end
|
|
|
|
describe 'GET /api/v1/accounts/{account.id}/inboxes/{inbox.id}/campaigns' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/campaigns"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:agent) { create(:user, account: account, role: :agent) }
|
|
let(:administrator) { create(:user, account: account, role: :administrator) }
|
|
|
|
let!(:campaign) { create(:campaign, account: account, inbox: inbox, trigger_rules: { url: 'https://test.com' }) }
|
|
|
|
it 'returns unauthorized for agents' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/campaigns",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'returns all campaigns belonging to the inbox to administrators' do
|
|
# create a random campaign
|
|
create(:campaign, account: account, trigger_rules: { url: 'https://test.com' })
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/campaigns",
|
|
headers: administrator.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
body = JSON.parse(response.body, symbolize_names: true)
|
|
expect(body.first[:id]).to eq(campaign.display_id)
|
|
expect(body.length).to eq(1)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'DELETE /api/v1/accounts/{account.id}/inboxes/{inbox.id}/avatar' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/avatar"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
before do
|
|
create(:inbox_member, user: agent, inbox: inbox)
|
|
inbox.avatar.attach(io: Rails.root.join('spec/assets/avatar.png').open, filename: 'avatar.png', content_type: 'image/png')
|
|
end
|
|
|
|
it 'delete inbox avatar for administrator user' do
|
|
perform_enqueued_jobs(only: DeleteObjectJob) do
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/avatar",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
end
|
|
|
|
expect { inbox.avatar.attachment.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
expect(response).to have_http_status(:success)
|
|
end
|
|
|
|
it 'returns unauthorized for agent user' do
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/avatar",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'DELETE /api/v1/accounts/{account.id}/inboxes/:id' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
|
|
it 'deletes inbox' do
|
|
expect(DeleteObjectJob).to receive(:perform_later).with(inbox, admin, anything).once
|
|
|
|
perform_enqueued_jobs(only: DeleteObjectJob) do
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
end
|
|
|
|
json_response = response.parsed_body
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(json_response['message']).to eq('Your inbox deletion request will be processed in some time.')
|
|
end
|
|
|
|
it 'is unable to delete inbox of another account' do
|
|
other_account = create(:account)
|
|
other_inbox = create(:inbox, account: other_account)
|
|
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{other_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
|
|
it 'is unable to delete inbox as agent' do
|
|
agent = create(:user, account: account, role: :agent)
|
|
|
|
delete "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'POST /api/v1/accounts/{account.id}/inboxes' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:valid_params) { { name: 'test', channel: { type: 'web_widget', website_url: 'test.com' } } }
|
|
|
|
it 'will not create inbox for agent' do
|
|
agent = create(:user, account: account, role: :agent)
|
|
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: agent.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'creates a webwidget inbox when administrator' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response).to conform_schema(200)
|
|
expect(response.body).to include('test.com')
|
|
end
|
|
|
|
it 'creates a email inbox when administrator' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: { name: 'test', channel: { type: 'email', email: 'test@test.com' } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response.body).to include('test@test.com')
|
|
end
|
|
|
|
it 'creates an api inbox when administrator' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: { name: 'API Inbox', channel: { type: 'api', webhook_url: 'http://test.com' } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response.body).to include('API Inbox')
|
|
end
|
|
|
|
it 'creates a line inbox when administrator' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: { name: 'Line Inbox',
|
|
channel: { type: 'line', line_channel_id: SecureRandom.uuid, line_channel_secret: SecureRandom.uuid,
|
|
line_channel_token: SecureRandom.uuid } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response.body).to include('Line Inbox')
|
|
expect(response.body).to include('callback_webhook_url')
|
|
end
|
|
|
|
it 'creates a sms inbox when administrator' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: { name: 'Sms Inbox',
|
|
channel: { type: 'sms', phone_number: '+123456789', provider_config: { test: 'test' } } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response.body).to include('Sms Inbox')
|
|
expect(response.body).to include('+123456789')
|
|
end
|
|
|
|
it 'creates the webwidget inbox that allow messages after conversation is resolved' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
expect(json_response['allow_messages_after_resolved']).to be true
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'PATCH /api/v1/accounts/{account.id}/inboxes/:id' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let!(:portal) { create(:portal, account_id: account.id) }
|
|
let(:valid_params) { { name: 'new test inbox', enable_auto_assignment: false, portal_id: portal.id } }
|
|
|
|
it 'will not update inbox for agent' do
|
|
agent = create(:user, account: account, role: :agent)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: agent.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'updates inbox when administrator' do
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(response).to conform_schema(200)
|
|
expect(inbox.reload.enable_auto_assignment).to be_falsey
|
|
expect(inbox.reload.portal_id).to eq(portal.id)
|
|
expect(response.parsed_body['name']).to eq 'new test inbox'
|
|
end
|
|
|
|
it 'updates api inbox when administrator' do
|
|
api_channel = create(:channel_api, account: account)
|
|
api_inbox = create(:inbox, channel: api_channel, account: account)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{api_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: { enable_auto_assignment: false, channel: { webhook_url: 'webhook.test', selected_feature_flags: [] } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(api_inbox.reload.enable_auto_assignment).to be_falsey
|
|
expect(api_channel.reload.webhook_url).to eq('webhook.test')
|
|
end
|
|
|
|
it 'updates whatsapp inbox when administrator' do
|
|
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook').to_return(status: 200, body: '', headers: {})
|
|
stub_request(:get, 'https://waba.360dialog.io/v1/configs/templates').to_return(status: 200, body: '', headers: {})
|
|
whatsapp_channel = create(:channel_whatsapp, account: account)
|
|
whatsapp_inbox = create(:inbox, channel: whatsapp_channel, account: account)
|
|
whatsapp_channel.prompt_reauthorization!
|
|
|
|
expect(whatsapp_channel).to be_reauthorization_required
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: { enable_auto_assignment: false, channel: { provider_config: { api_key: 'new_key' } } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(whatsapp_inbox.reload.enable_auto_assignment).to be_falsey
|
|
expect(whatsapp_channel.reload.provider_config['api_key']).to eq('new_key')
|
|
expect(whatsapp_channel.reload).not_to be_reauthorization_required
|
|
end
|
|
|
|
it 'updates twitter inbox when administrator' do
|
|
twitter_channel = create(:channel_twitter_profile, account: account, tweets_enabled: true)
|
|
twitter_inbox = create(:inbox, channel: twitter_channel, account: account)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{twitter_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: { channel: { tweets_enabled: false } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(twitter_channel.reload.tweets_enabled).to be(false)
|
|
end
|
|
|
|
it 'updates email inbox when administrator' do
|
|
email_channel = create(:channel_email, account: account)
|
|
email_inbox = create(:inbox, channel: email_channel, account: account)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: { enable_auto_assignment: false, channel: { email: 'emailtest@email.test' } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(email_inbox.reload.enable_auto_assignment).to be_falsey
|
|
expect(email_channel.reload.email).to eq('emailtest@email.test')
|
|
end
|
|
|
|
it 'updates twilio sms inbox when administrator' do
|
|
twilio_sms_channel = create(:channel_twilio_sms, account: account)
|
|
twilio_sms_inbox = create(:inbox, channel: twilio_sms_channel, account: account)
|
|
expect(twilio_sms_inbox.reload.channel.account_sid).not_to eq('account_sid')
|
|
expect(twilio_sms_inbox.reload.channel.auth_token).not_to eq('new_auth_token')
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{twilio_sms_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: { channel: { account_sid: 'account_sid', auth_token: 'new_auth_token' } },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(twilio_sms_inbox.reload.channel.account_sid).to eq('account_sid')
|
|
expect(twilio_sms_inbox.reload.channel.auth_token).to eq('new_auth_token')
|
|
end
|
|
|
|
it 'updates email inbox with imap when administrator' do
|
|
email_channel = create(:channel_email, account: account)
|
|
email_inbox = create(:inbox, channel: email_channel, account: account)
|
|
|
|
imap_connection = instance_double(Net::IMAP, disconnected?: false)
|
|
allow(Net::IMAP).to receive(:new).and_return(imap_connection)
|
|
allow(imap_connection).to receive(:login)
|
|
allow(imap_connection).to receive(:disconnect)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: {
|
|
channel: {
|
|
imap_enabled: true,
|
|
imap_address: 'imap.gmail.com',
|
|
imap_port: 993,
|
|
imap_login: 'imaptest@gmail.com',
|
|
imap_authentication: 'login'
|
|
}
|
|
},
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(email_channel.reload.imap_enabled).to be true
|
|
expect(email_channel.reload.imap_address).to eq('imap.gmail.com')
|
|
expect(email_channel.reload.imap_port).to eq(993)
|
|
expect(email_channel.reload.imap_authentication).to eq('login')
|
|
end
|
|
|
|
it 'updates avatar when administrator' do
|
|
# no avatar before upload
|
|
expect(inbox.avatar.attached?).to be(false)
|
|
file = fixture_file_upload(Rails.root.join('spec/assets/avatar.png'), 'image/png')
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: valid_params.merge(avatar: file),
|
|
headers: admin.create_new_auth_token
|
|
|
|
expect(response).to have_http_status(:success)
|
|
inbox.reload
|
|
expect(inbox.avatar.attached?).to be(true)
|
|
end
|
|
|
|
it 'updates working hours when administrator' do
|
|
params = {
|
|
working_hours: [{ 'day_of_week' => 0, 'open_hour' => 9, 'open_minutes' => 0, 'close_hour' => 17, 'close_minutes' => 0 }],
|
|
working_hours_enabled: true,
|
|
out_of_office_message: 'hello'
|
|
}
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: valid_params.merge(params),
|
|
headers: admin.create_new_auth_token
|
|
|
|
expect(response).to have_http_status(:success)
|
|
inbox.reload
|
|
expect(inbox.reload.weekly_schedule.find { |schedule| schedule['day_of_week'] == 0 }['open_hour']).to eq 9
|
|
end
|
|
|
|
it 'updates the webwidget inbox to disallow the messages after conversation is resolved' do
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: valid_params.merge({ allow_messages_after_resolved: false }),
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(inbox.reload.allow_messages_after_resolved).to be_falsey
|
|
end
|
|
end
|
|
|
|
context 'when an authenticated user updates email inbox' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:email_channel) { create(:channel_email, account: account) }
|
|
let(:email_inbox) { create(:inbox, channel: email_channel, account: account) }
|
|
|
|
it 'updates smtp configuration with starttls encryption' do
|
|
smtp_connection = double
|
|
allow(smtp_connection).to receive(:open_timeout=).and_return(10)
|
|
allow(smtp_connection).to receive(:start).and_return(true)
|
|
allow(smtp_connection).to receive(:finish).and_return(true)
|
|
allow(smtp_connection).to receive(:respond_to?).and_return(true)
|
|
allow(smtp_connection).to receive(:enable_starttls_auto).and_return(true)
|
|
allow(Net::SMTP).to receive(:new).and_return(smtp_connection)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: {
|
|
channel: {
|
|
smtp_enabled: true,
|
|
smtp_address: 'smtp.gmail.com',
|
|
smtp_port: 587,
|
|
smtp_login: 'smtptest@gmail.com',
|
|
smtp_enable_starttls_auto: true,
|
|
smtp_openssl_verify_mode: 'peer'
|
|
}
|
|
},
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(email_channel.reload.smtp_enabled).to be true
|
|
expect(email_channel.reload.smtp_address).to eq('smtp.gmail.com')
|
|
expect(email_channel.reload.smtp_port).to eq(587)
|
|
expect(email_channel.reload.smtp_enable_starttls_auto).to be true
|
|
expect(email_channel.reload.smtp_openssl_verify_mode).to eq('peer')
|
|
end
|
|
|
|
it 'updates smtp configuration with ssl/tls encryption' do
|
|
smtp_connection = double
|
|
allow(smtp_connection).to receive(:open_timeout=).and_return(10)
|
|
allow(smtp_connection).to receive(:start).and_return(true)
|
|
allow(smtp_connection).to receive(:finish).and_return(true)
|
|
allow(smtp_connection).to receive(:respond_to?).and_return(true)
|
|
allow(smtp_connection).to receive(:enable_tls).and_return(true)
|
|
allow(Net::SMTP).to receive(:new).and_return(smtp_connection)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: {
|
|
channel: {
|
|
smtp_enabled: true,
|
|
smtp_address: 'smtp.gmail.com',
|
|
smtp_login: 'smtptest@gmail.com',
|
|
smtp_port: 587,
|
|
smtp_enable_ssl_tls: true,
|
|
smtp_openssl_verify_mode: 'none'
|
|
}
|
|
},
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(email_channel.reload.smtp_enabled).to be true
|
|
expect(email_channel.reload.smtp_address).to eq('smtp.gmail.com')
|
|
expect(email_channel.reload.smtp_port).to eq(587)
|
|
expect(email_channel.reload.smtp_enable_ssl_tls).to be true
|
|
expect(email_channel.reload.smtp_openssl_verify_mode).to eq('none')
|
|
end
|
|
|
|
it 'updates smtp configuration with authentication mechanism' do
|
|
smtp_connection = double
|
|
allow(smtp_connection).to receive(:open_timeout=).and_return(10)
|
|
allow(smtp_connection).to receive(:start).and_return(true)
|
|
allow(smtp_connection).to receive(:finish).and_return(true)
|
|
allow(smtp_connection).to receive(:respond_to?).and_return(true)
|
|
allow(smtp_connection).to receive(:enable_starttls_auto).and_return(true)
|
|
allow(Net::SMTP).to receive(:new).and_return(smtp_connection)
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{email_inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
params: {
|
|
channel: {
|
|
smtp_enabled: true,
|
|
smtp_address: 'smtp.gmail.com',
|
|
smtp_port: 587,
|
|
smtp_email: 'smtptest@gmail.com',
|
|
smtp_authentication: 'plain'
|
|
}
|
|
},
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(email_channel.reload.smtp_enabled).to be true
|
|
expect(email_channel.reload.smtp_address).to eq('smtp.gmail.com')
|
|
expect(email_channel.reload.smtp_port).to eq(587)
|
|
expect(email_channel.reload.smtp_authentication).to eq('plain')
|
|
end
|
|
end
|
|
|
|
context 'when handling CSAT configuration' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
let(:csat_config) do
|
|
{
|
|
'display_type' => 'emoji',
|
|
'message' => 'How would you rate your experience?',
|
|
'survey_rules' => {
|
|
'operator' => 'contains',
|
|
'values' => %w[support help]
|
|
}
|
|
}
|
|
end
|
|
|
|
it 'successfully updates the inbox with CSAT configuration' do
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
end
|
|
|
|
context 'when CSAT is configured' do
|
|
before do
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
end
|
|
|
|
it 'returns configured CSAT settings in inbox details' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
expect(json_response['csat_survey_enabled']).to be true
|
|
|
|
saved_config = json_response['csat_config']
|
|
expect(saved_config).to be_present
|
|
expect(saved_config['display_type']).to eq('emoji')
|
|
end
|
|
|
|
it 'returns configured CSAT message' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
json_response = response.parsed_body
|
|
saved_config = json_response['csat_config']
|
|
expect(saved_config['message']).to eq('How would you rate your experience?')
|
|
end
|
|
|
|
it 'returns configured CSAT survey rules' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
json_response = response.parsed_body
|
|
saved_config = json_response['csat_config']
|
|
expect(saved_config['survey_rules']['operator']).to eq('contains')
|
|
expect(saved_config['survey_rules']['values']).to match_array(%w[support help])
|
|
end
|
|
|
|
it 'includes CSAT configuration in inbox list' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
inbox_list = response.parsed_body
|
|
found_inbox = inbox_list['payload'].find { |i| i['id'] == inbox.id }
|
|
|
|
expect(found_inbox['csat_survey_enabled']).to be true
|
|
expect(found_inbox['csat_config']).to be_present
|
|
expect(found_inbox['csat_config']['display_type']).to eq('emoji')
|
|
end
|
|
end
|
|
|
|
it 'successfully updates inbox with template configuration' do
|
|
csat_config_with_template = csat_config.merge({
|
|
'template' => {
|
|
'name' => 'custom_survey_template',
|
|
'template_id' => '123456789',
|
|
'language' => 'en',
|
|
'created_at' => Time.current.iso8601
|
|
}
|
|
})
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config_with_template
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
|
|
inbox.reload
|
|
template_config = inbox.csat_config['template']
|
|
expect(template_config).to be_present
|
|
expect(template_config['name']).to eq('custom_survey_template')
|
|
expect(template_config['template_id']).to eq('123456789')
|
|
expect(template_config['language']).to eq('en')
|
|
end
|
|
|
|
it 'returns template configuration in inbox details' do
|
|
csat_config_with_template = csat_config.merge({
|
|
'template' => {
|
|
'name' => 'custom_survey_template',
|
|
'template_id' => '123456789',
|
|
'language' => 'en',
|
|
'created_at' => Time.current.iso8601
|
|
}
|
|
})
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config_with_template
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
template_config = json_response['csat_config']['template']
|
|
|
|
expect(template_config).to be_present
|
|
expect(template_config['name']).to eq('custom_survey_template')
|
|
expect(template_config['template_id']).to eq('123456789')
|
|
expect(template_config['language']).to eq('en')
|
|
expect(template_config['created_at']).to be_present
|
|
end
|
|
|
|
it 'removes template configuration when not provided in update' do
|
|
# First set up template configuration
|
|
csat_config_with_template = csat_config.merge({
|
|
'template' => {
|
|
'name' => 'custom_survey_template',
|
|
'template_id' => '123456789'
|
|
}
|
|
})
|
|
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config_with_template
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
# Then update without template
|
|
patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}",
|
|
params: {
|
|
csat_survey_enabled: true,
|
|
csat_config: csat_config.merge({ 'message' => 'Updated message' })
|
|
},
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
|
|
inbox.reload
|
|
config = inbox.csat_config
|
|
expect(config['message']).to eq('Updated message')
|
|
expect(config['template']).to be_nil # Template should be removed when not provided
|
|
end
|
|
end
|
|
end
|
|
|
|
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"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
it 'returns empty when no agent bot is present' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/agent_bot",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
inbox_data = JSON.parse(response.body, symbolize_names: true)
|
|
expect(inbox_data[:agent_bot].blank?).to be(true)
|
|
end
|
|
|
|
it 'returns the agent bot attached to the inbox' do
|
|
agent_bot = create(:agent_bot)
|
|
create(:agent_bot_inbox, agent_bot: agent_bot, inbox: inbox)
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/agent_bot",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
inbox_data = JSON.parse(response.body, symbolize_names: true)
|
|
expect(inbox_data[:agent_bot][:name]).to eq agent_bot.name
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'POST /api/v1/accounts/{account.id}/inboxes/:id/set_agent_bot' do
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
let(:agent_bot) { create(:agent_bot) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/set_agent_bot"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
let(:admin) { create(:user, account: account, role: :administrator) }
|
|
let(:valid_params) { { agent_bot: agent_bot.id } }
|
|
|
|
it 'sets the agent bot' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/set_agent_bot",
|
|
headers: admin.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(inbox.reload.agent_bot.id).to eq agent_bot.id
|
|
end
|
|
|
|
it 'throw error when invalid agent bot id' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/set_agent_bot",
|
|
headers: admin.create_new_auth_token,
|
|
params: { agent_bot: 0 },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
|
|
it 'disconnects the agent bot' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/set_agent_bot",
|
|
headers: admin.create_new_auth_token,
|
|
params: { agent_bot: nil },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
expect(inbox.reload.agent_bot).to be_falsey
|
|
end
|
|
|
|
it 'will not update agent bot when its an agent' do
|
|
agent = create(:user, account: account, role: :agent)
|
|
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/set_agent_bot",
|
|
headers: agent.create_new_auth_token,
|
|
params: valid_params,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'does not allow binding an agent bot from another account' do
|
|
other_account = create(:account)
|
|
foreign_bot = create(:agent_bot, account: other_account)
|
|
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}/set_agent_bot",
|
|
headers: admin.create_new_auth_token,
|
|
params: { agent_bot: foreign_bot.id },
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:not_found)
|
|
expect(inbox.reload.agent_bot).to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'POST /api/v1/accounts/{account.id}/inboxes/:id/sync_templates' do
|
|
let(:whatsapp_channel) do
|
|
create(:channel_whatsapp, account: account, provider: 'whatsapp_cloud', sync_templates: false, validate_provider_config: false)
|
|
end
|
|
let(:whatsapp_inbox) { create(:inbox, account: account, channel: whatsapp_channel) }
|
|
let(:non_whatsapp_inbox) { create(:inbox, account: account) }
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/sync_templates"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated agent' do
|
|
it 'returns unauthorized for agent' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/sync_templates",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated administrator' do
|
|
context 'with WhatsApp inbox' do
|
|
it 'successfully initiates template sync' do
|
|
expect(Channels::Whatsapp::TemplatesSyncJob).to receive(:perform_later).with(whatsapp_channel)
|
|
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/sync_templates",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
expect(json_response['message']).to eq('Template sync initiated successfully')
|
|
end
|
|
|
|
it 'handles job errors gracefully' do
|
|
allow(Channels::Whatsapp::TemplatesSyncJob).to receive(:perform_later).and_raise(StandardError, 'Job failed')
|
|
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/sync_templates",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:internal_server_error)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to eq('Job failed')
|
|
end
|
|
end
|
|
|
|
context 'with non-WhatsApp inbox' do
|
|
it 'returns unprocessable entity error' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/#{non_whatsapp_inbox.id}/sync_templates",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to eq('Template sync is only available for WhatsApp channels')
|
|
end
|
|
end
|
|
|
|
context 'with non-existent inbox' do
|
|
it 'returns not found error' do
|
|
post "/api/v1/accounts/#{account.id}/inboxes/999999/sync_templates",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v1/accounts/{account.id}/inboxes/{inbox.id}/health' do
|
|
let(:whatsapp_channel) do
|
|
create(:channel_whatsapp, account: account, provider: 'whatsapp_cloud', sync_templates: false, validate_provider_config: false)
|
|
end
|
|
let(:whatsapp_inbox) { create(:inbox, account: account, channel: whatsapp_channel) }
|
|
let(:non_whatsapp_inbox) { create(:inbox, account: account) }
|
|
let(:health_service) { instance_double(Whatsapp::HealthService) }
|
|
let(:health_data) do
|
|
{
|
|
display_phone_number: '+1234567890',
|
|
verified_name: 'Test Business',
|
|
name_status: 'APPROVED',
|
|
quality_rating: 'GREEN',
|
|
messaging_limit_tier: 'TIER_1000',
|
|
account_mode: 'LIVE',
|
|
business_id: 'business123'
|
|
}
|
|
end
|
|
|
|
before do
|
|
allow(Whatsapp::HealthService).to receive(:new).and_return(health_service)
|
|
allow(health_service).to receive(:fetch_health_status).and_return(health_data)
|
|
end
|
|
|
|
context 'when it is an unauthenticated user' do
|
|
it 'returns unauthorized' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health"
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
context 'when it is an authenticated user' do
|
|
context 'with WhatsApp inbox' do
|
|
it 'returns health data for administrator' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
expect(json_response).to include(
|
|
'display_phone_number' => '+1234567890',
|
|
'verified_name' => 'Test Business',
|
|
'name_status' => 'APPROVED',
|
|
'quality_rating' => 'GREEN',
|
|
'messaging_limit_tier' => 'TIER_1000',
|
|
'account_mode' => 'LIVE',
|
|
'business_id' => 'business123'
|
|
)
|
|
end
|
|
|
|
it 'returns health data for agent with inbox access' do
|
|
create(:inbox_member, user: agent, inbox: whatsapp_inbox)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
json_response = response.parsed_body
|
|
expect(json_response['display_phone_number']).to eq('+1234567890')
|
|
end
|
|
|
|
it 'returns unauthorized for agent without inbox access' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'calls the health service with correct channel' do
|
|
expect(Whatsapp::HealthService).to receive(:new).with(whatsapp_channel).and_return(health_service)
|
|
expect(health_service).to receive(:fetch_health_status)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:success)
|
|
end
|
|
|
|
it 'handles service errors gracefully' do
|
|
allow(health_service).to receive(:fetch_health_status).and_raise(StandardError, 'API Error')
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_inbox.id}/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to include('API Error')
|
|
end
|
|
end
|
|
|
|
context 'with non-WhatsApp inbox' do
|
|
it 'returns bad request error for administrator' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{non_whatsapp_inbox.id}/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:bad_request)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to eq('Health data only available for WhatsApp Cloud API channels')
|
|
end
|
|
|
|
it 'returns bad request error for agent' do
|
|
create(:inbox_member, user: agent, inbox: non_whatsapp_inbox)
|
|
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{non_whatsapp_inbox.id}/health",
|
|
headers: agent.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:bad_request)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to eq('Health data only available for WhatsApp Cloud API channels')
|
|
end
|
|
end
|
|
|
|
context 'with WhatsApp non-cloud inbox' do
|
|
let(:whatsapp_default_channel) do
|
|
create(:channel_whatsapp, account: account, provider: 'default', sync_templates: false, validate_provider_config: false)
|
|
end
|
|
let(:whatsapp_default_inbox) { create(:inbox, account: account, channel: whatsapp_default_channel) }
|
|
|
|
it 'returns bad request error for non-cloud provider' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/#{whatsapp_default_inbox.id}/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:bad_request)
|
|
json_response = response.parsed_body
|
|
expect(json_response['error']).to eq('Health data only available for WhatsApp Cloud API channels')
|
|
end
|
|
end
|
|
|
|
context 'with non-existent inbox' do
|
|
it 'returns not found error' do
|
|
get "/api/v1/accounts/#{account.id}/inboxes/999999/health",
|
|
headers: admin.create_new_auth_token,
|
|
as: :json
|
|
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|