diff --git a/app/controllers/api/v1/accounts/contacts_controller.rb b/app/controllers/api/v1/accounts/contacts_controller.rb index 561b224c3..0c9341b08 100644 --- a/app/controllers/api/v1/accounts/contacts_controller.rb +++ b/app/controllers/api/v1/accounts/contacts_controller.rb @@ -50,6 +50,10 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController def show; end + def filter + @contacts = Current.account.contacts.limit(10) + end + def contactable_inboxes @all_contactable_inboxes = Contacts::ContactableInboxesService.new(contact: @contact).get @contactable_inboxes = @all_contactable_inboxes.select { |contactable_inbox| policy(contactable_inbox[:inbox]).show? } diff --git a/app/controllers/api/v1/accounts/conversations_controller.rb b/app/controllers/api/v1/accounts/conversations_controller.rb index 89d48e544..db9f65b41 100644 --- a/app/controllers/api/v1/accounts/conversations_controller.rb +++ b/app/controllers/api/v1/accounts/conversations_controller.rb @@ -2,7 +2,7 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro include Events::Types include DateRangeHelper - before_action :conversation, except: [:index, :meta, :search, :create] + before_action :conversation, except: [:index, :meta, :search, :create, :filter] before_action :contact_inbox, only: [:create] def index @@ -31,6 +31,10 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro def show; end + def filter + @conversations = Current.account.conversations.limit(10) + end + def mute @conversation.mute! head :ok diff --git a/app/policies/contact_policy.rb b/app/policies/contact_policy.rb index 9013014d7..67ab23c5d 100644 --- a/app/policies/contact_policy.rb +++ b/app/policies/contact_policy.rb @@ -15,6 +15,10 @@ class ContactPolicy < ApplicationPolicy true end + def filter? + true + end + def update? true end diff --git a/app/views/api/v1/accounts/contacts/filter.json.jbuilder b/app/views/api/v1/accounts/contacts/filter.json.jbuilder new file mode 100644 index 000000000..87d953b5b --- /dev/null +++ b/app/views/api/v1/accounts/contacts/filter.json.jbuilder @@ -0,0 +1,3 @@ +json.array! @contacts do |contact| + json.partial! 'api/v1/models/contact.json.jbuilder', resource: contact +end diff --git a/app/views/api/v1/accounts/conversations/filter.json.jbuilder b/app/views/api/v1/accounts/conversations/filter.json.jbuilder new file mode 100644 index 000000000..6b8baf3ce --- /dev/null +++ b/app/views/api/v1/accounts/conversations/filter.json.jbuilder @@ -0,0 +1,3 @@ +json.array! @conversations do |conversation| + json.partial! 'api/v1/models/conversation.json.jbuilder', conversation: conversation +end diff --git a/app/views/api/v1/accounts/conversations/search.json.jbuilder b/app/views/api/v1/accounts/conversations/search.json.jbuilder index ab9114ad7..ac70d3a55 100644 --- a/app/views/api/v1/accounts/conversations/search.json.jbuilder +++ b/app/views/api/v1/accounts/conversations/search.json.jbuilder @@ -5,26 +5,6 @@ json.meta do end json.payload do json.array! @conversations do |conversation| - json.id conversation.display_id - json.created_at conversation.created_at.to_i - json.contact do - json.id conversation.contact.id - json.name conversation.contact.name - end - json.inbox do - json.id conversation.inbox.id - json.name conversation.inbox.name - json.channel_type conversation.inbox.channel_type - end - json.messages do - json.array! conversation.messages do |message| - json.content message.content - json.id message.id - json.sender_name message.sender.name if message.sender - json.message_type message.message_type_before_type_cast - json.created_at message.created_at.to_i - end - end - json.account_id conversation.account_id + json.partial! 'api/v1/models/conversation.json.jbuilder', conversation: conversation end end diff --git a/app/views/api/v1/models/_conversation.json.jbuilder b/app/views/api/v1/models/_conversation.json.jbuilder new file mode 100644 index 000000000..0951892a6 --- /dev/null +++ b/app/views/api/v1/models/_conversation.json.jbuilder @@ -0,0 +1,21 @@ +json.id conversation.display_id +json.created_at conversation.created_at.to_i +json.contact do + json.id conversation.contact.id + json.name conversation.contact.name +end +json.inbox do + json.id conversation.inbox.id + json.name conversation.inbox.name + json.channel_type conversation.inbox.channel_type +end +json.messages do + json.array! conversation.messages do |message| + json.content message.content + json.id message.id + json.sender_name message.sender.name if message.sender + json.message_type message.message_type_before_type_cast + json.created_at message.created_at.to_i + end +end +json.account_id conversation.account_id diff --git a/config/routes.rb b/config/routes.rb index 3d629d2fd..61a5d15a5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -58,8 +58,11 @@ Rails.application.routes.draw do resource :twilio_channel, only: [:create] end resources :conversations, only: [:index, :create, :show] do - get 'meta', on: :collection - get 'search', on: :collection + collection do + get :meta + get :search + get :filter + end scope module: :conversations do resources :messages, only: [:index, :create, :destroy] resources :assignments, only: [:create] @@ -80,6 +83,7 @@ Rails.application.routes.draw do collection do get :active get :search + get :filter post :import end member do diff --git a/lib/filters/conversation_filters.json b/lib/filters/conversation_filters.json new file mode 100644 index 000000000..6e493e57a --- /dev/null +++ b/lib/filters/conversation_filters.json @@ -0,0 +1,92 @@ +{ + "conversations": [ + { + "attribute_key": "status", + "attribute_name": "Status", + "input_type": "multi_select", + "data_type": "text", + "filter_operators": [ "equal_to", "not_equal_to" ], + "attribute_type": "standard" + }, + { + "attribute_key": "assigne", + "attribute_name": "Assignee Name", + "input_type": "search_box with name tags/plain text", + "data_type": "text", + "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain", "is_present", "is_not_present" ], + "attribute_type": "standard" + }, + { + "attribute_key": "contact", + "attribute_name": "Contact Name", + "input_type": "plain_text", + "data_type": "text", + "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain", "is_present", "is_not_present" ], + "attribute_type": "standard" + }, + { + "attribute_key": "inbox", + "attribute_name": "Inbox Name", + "input_type": "search_box", + "data_type": "text", + "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain", "is_present", "is_not_present" ], + "attribute_type": "standard" + }, + { + "attribute_key": "team_id", + "attribute_name": "Team Name", + "input_type": "search_box", + "data_type": "number", + "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain", "is_present", "is_not_present" ], + "attribute_type": "standard" + }, + { + "attribute_key": "id", + "attribute_name": "Conversation Identifier", + "input_type": "textbox", + "data_type": "Number", + "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain", "is_present", "is_not_present" ], + "attribute_type": "standard" + }, + { + "attribute_key": "campaign_id", + "attribute_name": "Campaign Name", + "input_type": "textbox", + "data_type": "Number", + "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain", "is_present", "is_not_present" ], + "attribute_type": "standard" + }, + { + "attribute_key": "labels", + "attribute_name": "Labels", + "input_type": "tags", + "data_type": "text", + "filter_operators": ["exactly_equal_to", "contains", "does_not_contain" ], + "attribute_type": "standard" + }, + { + "attribute_key": "browser", + "attribute_name": "browser", + "input_type": "textbox", + "data_type": "text", + "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain" ], + "attribute_type": "additional_attributes" + }, + { + "attribute_key": "country_code", + "attribute_name": "Country Name", + "input_type": "textbox", + "data_type": "text", + "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain", "present", "is_not_present" ], + "attribute_type": "additional_attributes" + }, + { + "attribute_key": "referer", + "attribute_name": "Referer link", + "input_type": "textbox", + "data_type": "link", + "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain", "present", "is_not_present" ], + "attribute_type": "additional_attributes" + } + ] +} diff --git a/spec/controllers/api/v1/accounts/contacts_controller_spec.rb b/spec/controllers/api/v1/accounts/contacts_controller_spec.rb index 13d2649f3..dc7d81146 100644 --- a/spec/controllers/api/v1/accounts/contacts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/contacts_controller_spec.rb @@ -218,6 +218,33 @@ RSpec.describe 'Contacts API', type: :request do end end + describe 'GET /api/v1/accounts/{account.id}/contacts/filter' do + context 'when it is an unauthenticated user' do + it 'returns unauthorized' do + get "/api/v1/accounts/#{account.id}/contacts/filter" + + 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, :with_email, account: account) } + let!(:contact2) { create(:contact, :with_email, name: 'testcontact', account: account, email: 'test@test.com') } + + it 'returns all contacts when query is empty' do + get "/api/v1/accounts/#{account.id}/contacts/filter", + params: { q: [] }, + 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).to include(contact1.email) + end + end + end + describe 'GET /api/v1/accounts/{account.id}/contacts/:id' do let!(:contact) { create(:contact, account: account) } diff --git a/spec/controllers/api/v1/accounts/conversations_controller_spec.rb b/spec/controllers/api/v1/accounts/conversations_controller_spec.rb index 025932175..dafec9ea7 100644 --- a/spec/controllers/api/v1/accounts/conversations_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/conversations_controller_spec.rb @@ -109,6 +109,40 @@ RSpec.describe 'Conversations API', type: :request do end end + describe 'GET /api/v1/accounts/{account.id}/conversations/filter' do + context 'when it is an unauthenticated user' do + it 'returns unauthorized' do + get "/api/v1/accounts/#{account.id}/conversations/filter", params: { q: 'test' } + + 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) } + + before do + conversation = create(:conversation, account: account) + create(:message, conversation: conversation, account: account, content: 'test1') + create(:message, conversation: conversation, account: account, content: 'test2') + create(:inbox_member, user: agent, inbox: conversation.inbox) + end + + it 'returns all conversations with empty query' do + get "/api/v1/accounts/#{account.id}/conversations/filter", + headers: agent.create_new_auth_token, + params: { q: 'test1' }, + as: :json + + expect(response).to have_http_status(:success) + response_data = JSON.parse(response.body, symbolize_names: true) + + expect(response_data.count).to eq(1) + expect(response_data[0][:messages][0][:content]).to include(Message.first.content) + end + end + end + describe 'GET /api/v1/accounts/{account.id}/conversations/:id' do let(:conversation) { create(:conversation, account: account) }