From a6a62d92bfbcfa0847fcfb8c8ca8732b5ca22deb Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Mon, 10 Aug 2020 12:15:29 +0530 Subject: [PATCH] chore: Add Additional Contact APIs (#1130) Co-authored-by: Pranav Raj Sreepuram --- app/builders/messages/message_builder.rb | 2 +- .../contacts/contact_inboxes_controller.rb | 26 +++++++++++ .../api/v1/accounts/contacts_controller.rb | 8 +++- app/policies/contact_policy.rb | 4 ++ .../contact_inboxes/create.json.jbuilder | 1 + .../v1/accounts/contacts/search.json.jbuilder | 5 +++ .../api/v1/models/_contact.json.jbuilder | 5 +++ .../v1/models/_contact_inbox.json.jbuilder | 2 + config/routes.rb | 4 ++ .../contact_inboxes_controller_spec.rb | 43 +++++++++++++++++++ .../v1/accounts/contacts_controller_spec.rb | 32 +++++++++++++- 11 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 app/controllers/api/v1/accounts/contacts/contact_inboxes_controller.rb create mode 100644 app/views/api/v1/accounts/contacts/contact_inboxes/create.json.jbuilder create mode 100644 app/views/api/v1/accounts/contacts/search.json.jbuilder create mode 100644 app/views/api/v1/models/_contact_inbox.json.jbuilder create mode 100644 spec/controllers/api/v1/accounts/contacts/contact_inboxes_controller_spec.rb diff --git a/app/builders/messages/message_builder.rb b/app/builders/messages/message_builder.rb index e53bcf377..ff730893c 100644 --- a/app/builders/messages/message_builder.rb +++ b/app/builders/messages/message_builder.rb @@ -31,7 +31,7 @@ class Messages::MessageBuilder private def message_type - if @conversation.inbox.channel.class != Channel::Api && @message_type == 'incoming' + if @conversation.inbox.channel_type != 'Channel::Api' && @message_type == 'incoming' raise StandardError, 'Incoming messages are only allowed in Api inboxes' end diff --git a/app/controllers/api/v1/accounts/contacts/contact_inboxes_controller.rb b/app/controllers/api/v1/accounts/contacts/contact_inboxes_controller.rb new file mode 100644 index 000000000..7875b0f10 --- /dev/null +++ b/app/controllers/api/v1/accounts/contacts/contact_inboxes_controller.rb @@ -0,0 +1,26 @@ +class Api::V1::Accounts::Contacts::ContactInboxesController < Api::V1::Accounts::BaseController + before_action :ensure_contact + before_action :ensure_inbox, only: [:create] + before_action :validate_channel_type + + def create + source_id = params[:source_id] || SecureRandom.uuid + @contact_inbox = ContactInbox.create(contact: @contact, inbox: @inbox, source_id: source_id) + end + + private + + def validate_channel_type + return if @inbox.channel_type == 'Channel::Api' + + render json: { error: 'Contact Inbox creation is only allowed in API inboxes' }, status: :unprocessable_entity + end + + def ensure_inbox + @inbox = Current.account.inboxes.find(params[:inbox_id]) + end + + def ensure_contact + @contact = Current.account.contacts.find(params[:contact_id]) + end +end diff --git a/app/controllers/api/v1/accounts/contacts_controller.rb b/app/controllers/api/v1/accounts/contacts_controller.rb index 7f7e7afdb..eef50ef11 100644 --- a/app/controllers/api/v1/accounts/contacts_controller.rb +++ b/app/controllers/api/v1/accounts/contacts_controller.rb @@ -22,6 +22,12 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController @contact.update!(contact_params) end + def search + render json: { error: 'Specify search string with parameter q' }, status: :unprocessable_entity if params[:q].blank? && return + + @contacts = Current.account.contacts.where('name LIKE :search OR email LIKE :search', search: "%#{params[:q]}%") + end + private def check_authorization @@ -31,7 +37,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController def build_contact_inbox return if params[:inbox_id].blank? - inbox = Inbox.find(params[:inbox_id]) + inbox = Current.account.inboxes.find(params[:inbox_id]) source_id = params[:source_id] || SecureRandom.uuid ContactInbox.create(contact: @contact, inbox: inbox, source_id: source_id) end diff --git a/app/policies/contact_policy.rb b/app/policies/contact_policy.rb index dc1c3b7d1..722e70e0b 100644 --- a/app/policies/contact_policy.rb +++ b/app/policies/contact_policy.rb @@ -3,6 +3,10 @@ class ContactPolicy < ApplicationPolicy true end + def search? + true + end + def update? true end diff --git a/app/views/api/v1/accounts/contacts/contact_inboxes/create.json.jbuilder b/app/views/api/v1/accounts/contacts/contact_inboxes/create.json.jbuilder new file mode 100644 index 000000000..7d325d8fc --- /dev/null +++ b/app/views/api/v1/accounts/contacts/contact_inboxes/create.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'api/v1/models/contact_inbox.json.jbuilder', resource: @contact_inbox diff --git a/app/views/api/v1/accounts/contacts/search.json.jbuilder b/app/views/api/v1/accounts/contacts/search.json.jbuilder new file mode 100644 index 000000000..892e5fbdd --- /dev/null +++ b/app/views/api/v1/accounts/contacts/search.json.jbuilder @@ -0,0 +1,5 @@ +json.payload do + json.array! @contacts do |contact| + json.partial! 'api/v1/models/contact.json.jbuilder', resource: contact + end +end diff --git a/app/views/api/v1/models/_contact.json.jbuilder b/app/views/api/v1/models/_contact.json.jbuilder index a9152712e..80f449a13 100644 --- a/app/views/api/v1/models/_contact.json.jbuilder +++ b/app/views/api/v1/models/_contact.json.jbuilder @@ -5,3 +5,8 @@ json.id resource.id json.name resource.name json.phone_number resource.phone_number json.thumbnail resource.avatar_url +json.contact_inboxes do + json.array! resource.contact_inboxes do |contact_inbox| + json.partial! 'api/v1/models/contact_inbox.json.jbuilder', resource: contact_inbox + end +end diff --git a/app/views/api/v1/models/_contact_inbox.json.jbuilder b/app/views/api/v1/models/_contact_inbox.json.jbuilder new file mode 100644 index 000000000..c4b34f15a --- /dev/null +++ b/app/views/api/v1/models/_contact_inbox.json.jbuilder @@ -0,0 +1,2 @@ +json.source_id resource.source_id +json.inbox resource.inbox diff --git a/config/routes.rb b/config/routes.rb index 0023e81ad..df64f88d4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -61,8 +61,12 @@ Rails.application.routes.draw do end resources :contacts, only: [:index, :show, :update, :create] do + collection do + get :search + end scope module: :contacts do resources :conversations, only: [:index] + resources :contact_inboxes, only: [:create] end end diff --git a/spec/controllers/api/v1/accounts/contacts/contact_inboxes_controller_spec.rb b/spec/controllers/api/v1/accounts/contacts/contact_inboxes_controller_spec.rb new file mode 100644 index 000000000..5d2288aeb --- /dev/null +++ b/spec/controllers/api/v1/accounts/contacts/contact_inboxes_controller_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' + +RSpec.describe '/api/v1/accounts/{account.id}/contacts/:id/contact_inboxes', type: :request do + let(:account) { create(:account) } + let(:contact) { create(:contact, account: account) } + let(:inbox_1) { create(:inbox, account: account) } + let(:channel_api) { create(:channel_api, account: account) } + let(:user) { create(:user, account: account) } + + describe 'GET /api/v1/accounts/{account.id}/contacts/:id/contact_inboxes' do + context 'when unauthenticated user' do + it 'returns unauthorized' do + post "/api/v1/accounts/#{account.id}/contacts/#{contact.id}/contact_inboxes" + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when user is logged in' do + it 'creates a contact inbox' do + 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, + as: :json + end.to change(ContactInbox, :count).by(1) + + expect(response).to have_http_status(:success) + expect(contact.reload.contact_inboxes.map(&:inbox_id)).to include(channel_api.inbox.id) + end + + it 'throws error when its not an api inbox' do + expect do + post "/api/v1/accounts/#{account.id}/contacts/#{contact.id}/contact_inboxes", + params: { inbox_id: inbox_1.id }, + headers: user.create_new_auth_token, + as: :json + end.to change(ContactInbox, :count).by(0) + + expect(response).to have_http_status(:unprocessable_entity) + end + end + end +end diff --git a/spec/controllers/api/v1/accounts/contacts_controller_spec.rb b/spec/controllers/api/v1/accounts/contacts_controller_spec.rb index 16cd13593..c1dfc83e0 100644 --- a/spec/controllers/api/v1/accounts/contacts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/contacts_controller_spec.rb @@ -15,14 +15,44 @@ RSpec.describe 'Contacts API', type: :request do context 'when it is an authenticated user' do let(:admin) { create(:user, account: account, role: :administrator) } let!(:contact) { create(:contact, account: account) } + let!(:contact_inbox) { create(:contact_inbox, contact: contact) } - it 'returns all contacts' do + it 'returns all contacts with contact inboxes' do get "/api/v1/accounts/#{account.id}/contacts", headers: admin.create_new_auth_token, as: :json expect(response).to have_http_status(:success) expect(response.body).to include(contact.email) + expect(response.body).to include(contact_inbox.source_id) + expect(response.body).to include(contact_inbox.inbox.name) + end + end + end + + describe 'GET /api/v1/accounts/{account.id}/contacts/search' do + context 'when it is an unauthenticated user' do + it 'returns unauthorized' do + get "/api/v1/accounts/#{account.id}/contacts/search" + + 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!(:contact1) { create(:contact, account: account) } + let!(:contact2) { create(:contact, account: account, email: 'test@test.com') } + + it 'returns all contacts with contact inboxes' do + get "/api/v1/accounts/#{account.id}/contacts/search", + params: { q: contact2.email }, + headers: admin.create_new_auth_token, + as: :json + + expect(response).to have_http_status(:success) + expect(response.body).to include(contact2.email) + expect(response.body).not_to include(contact1.email) end end end