feat: Ability to search conversation with message content (#1265)
- API end point which takes message content as search parameter - end point supports additional filtering with labels and inbox ids - swagger doc
This commit is contained in:
parent
bc8becf49c
commit
532331edb6
7 changed files with 122 additions and 9 deletions
|
@ -15,6 +15,12 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||||
@conversations_count = result[:count]
|
@conversations_count = result[:count]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def search
|
||||||
|
result = conversation_finder.perform
|
||||||
|
@conversations = result[:conversations]
|
||||||
|
@conversations_count = result[:count]
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@conversation = ::Conversation.create!(conversation_params)
|
@conversation = ::Conversation.create!(conversation_params)
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,6 +27,7 @@ class ConversationFinder
|
||||||
find_all_conversations
|
find_all_conversations
|
||||||
filter_by_status
|
filter_by_status
|
||||||
filter_by_labels if params[:labels]
|
filter_by_labels if params[:labels]
|
||||||
|
filter_by_query if params[:q]
|
||||||
|
|
||||||
mine_count, unassigned_count, all_count = set_count_for_all_conversations
|
mine_count, unassigned_count, all_count = set_count_for_all_conversations
|
||||||
|
|
||||||
|
@ -76,6 +77,12 @@ class ConversationFinder
|
||||||
@conversations
|
@conversations
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def filter_by_query
|
||||||
|
@conversations = @conversations.joins(:messages).where('messages.content LIKE :search',
|
||||||
|
search: "%#{params[:q]}%").includes(:messages).where('messages.content LIKE :search',
|
||||||
|
search: "%#{params[:q]}%")
|
||||||
|
end
|
||||||
|
|
||||||
def filter_by_status
|
def filter_by_status
|
||||||
@conversations = @conversations.where(status: params[:status] || DEFAULT_STATUS)
|
@conversations = @conversations.where(status: params[:status] || DEFAULT_STATUS)
|
||||||
end
|
end
|
||||||
|
|
22
app/views/api/v1/accounts/conversations/search.json.jbuilder
Normal file
22
app/views/api/v1/accounts/conversations/search.json.jbuilder
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
json.data do
|
||||||
|
json.meta do
|
||||||
|
json.mine_count @conversations_count[:mine_count]
|
||||||
|
json.unassigned_count @conversations_count[:unassigned_count]
|
||||||
|
json.all_count @conversations_count[:all_count]
|
||||||
|
end
|
||||||
|
json.payload do
|
||||||
|
json.array! @conversations do |conversation|
|
||||||
|
json.inbox_id conversation.inbox_id
|
||||||
|
json.messages conversation.messages
|
||||||
|
json.status conversation.status
|
||||||
|
json.muted conversation.muted?
|
||||||
|
json.can_reply conversation.can_reply?
|
||||||
|
json.timestamp conversation.messages.last.try(:created_at).try(:to_i)
|
||||||
|
json.contact_last_seen_at conversation.contact_last_seen_at.to_i
|
||||||
|
json.agent_last_seen_at conversation.agent_last_seen_at.to_i
|
||||||
|
json.additional_attributes conversation.additional_attributes
|
||||||
|
json.account_id conversation.account_id
|
||||||
|
json.labels conversation.label_list
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -47,6 +47,7 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
resources :conversations, only: [:index, :create, :show] do
|
resources :conversations, only: [:index, :create, :show] do
|
||||||
get 'meta', on: :collection
|
get 'meta', on: :collection
|
||||||
|
get 'search', on: :collection
|
||||||
scope module: :conversations do
|
scope module: :conversations do
|
||||||
resources :messages, only: [:index, :create]
|
resources :messages, only: [:index, :create]
|
||||||
resources :assignments, only: [:create]
|
resources :assignments, only: [:create]
|
||||||
|
|
|
@ -59,6 +59,39 @@ RSpec.describe 'Conversations API', type: :request do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'GET /api/v1/accounts/{account.id}/conversations/search' do
|
||||||
|
context 'when it is an unauthenticated user' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get "/api/v1/accounts/#{account.id}/conversations/search", 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 messages containing the search query' do
|
||||||
|
get "/api/v1/accounts/#{account.id}/conversations/search",
|
||||||
|
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)[:data]
|
||||||
|
expect(response_data[:meta][:all_count]).to eq(1)
|
||||||
|
expect(response_data[:payload].first[:messages].first[:content]).to eq 'test1'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'GET /api/v1/accounts/{account.id}/conversations/:id' do
|
describe 'GET /api/v1/accounts/{account.id}/conversations/:id' do
|
||||||
let(:conversation) { create(:conversation, account: account) }
|
let(:conversation) { create(:conversation, account: account) }
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,48 @@ get:
|
||||||
$ref: '#/definitions/bad_request_error'
|
$ref: '#/definitions/bad_request_error'
|
||||||
description: Access denied
|
description: Access denied
|
||||||
|
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Conversation
|
||||||
|
operationId: conversationSearch
|
||||||
|
description: Search for conversations containing a messages with the query string
|
||||||
|
summary: Conversations Search
|
||||||
|
parameters:
|
||||||
|
- name: q
|
||||||
|
in: query
|
||||||
|
type: string
|
||||||
|
- name: assignee_type
|
||||||
|
in: query
|
||||||
|
type: string
|
||||||
|
enum: ['me', 'unassigned', 'all']
|
||||||
|
- name: status
|
||||||
|
in: query
|
||||||
|
type: string
|
||||||
|
enum: ['open', 'resolved', 'bot']
|
||||||
|
- name: page
|
||||||
|
in: query
|
||||||
|
type: integer
|
||||||
|
- name: inbox_id
|
||||||
|
in: query
|
||||||
|
type: integer
|
||||||
|
- name: labels
|
||||||
|
in: query
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: Success
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/conversation_list'
|
||||||
|
400:
|
||||||
|
description: Bad Request Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/bad_request_error'
|
||||||
|
description: Access denied
|
||||||
|
|
||||||
|
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Conversation
|
- Conversation
|
||||||
|
|
|
@ -283,10 +283,15 @@
|
||||||
"tags": [
|
"tags": [
|
||||||
"Conversation"
|
"Conversation"
|
||||||
],
|
],
|
||||||
"operationId": "conversationList",
|
"operationId": "conversationSearch",
|
||||||
"description": "List all the conversations with pagination",
|
"description": "Search for conversations containing a messages with the query string",
|
||||||
"summary": "Conversations List",
|
"summary": "Conversations Search",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "q",
|
||||||
|
"in": "query",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "assignee_type",
|
"name": "assignee_type",
|
||||||
"in": "query",
|
"in": "query",
|
||||||
|
@ -295,8 +300,7 @@
|
||||||
"me",
|
"me",
|
||||||
"unassigned",
|
"unassigned",
|
||||||
"all"
|
"all"
|
||||||
],
|
]
|
||||||
"required": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "status",
|
"name": "status",
|
||||||
|
@ -306,14 +310,12 @@
|
||||||
"open",
|
"open",
|
||||||
"resolved",
|
"resolved",
|
||||||
"bot"
|
"bot"
|
||||||
],
|
]
|
||||||
"required": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"type": "integer",
|
"type": "integer"
|
||||||
"required": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "inbox_id",
|
"name": "inbox_id",
|
||||||
|
|
Loading…
Reference in a new issue