feat: Add filter APIs for Contacts and Conversations (#3264)

This commit is contained in:
Tejaswini Chile
2021-11-01 13:57:04 +05:30
committed by GitHub
parent 68fa694268
commit 372bd75028
13 changed files with 470 additions and 19 deletions

View File

@@ -51,7 +51,10 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
def show; end
def filter
@contacts = Current.account.contacts.limit(10)
result = ::Contacts::FilterService.new(params.permit!, current_user).perform
contacts = result[:contacts]
@contacts_count = result[:count]
@contacts = fetch_contacts_with_conversation_count(contacts)
end
def contactable_inboxes

View File

@@ -32,7 +32,9 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
def show; end
def filter
@conversations = Current.account.conversations.limit(10)
result = ::Conversations::FilterService.new(params.permit!, current_user).perform
@conversations = result[:conversations]
@conversations_count = result[:count]
end
def mute

View File

@@ -0,0 +1,44 @@
class Contacts::FilterService < FilterService
def perform
@contacts = contact_query_builder
{
contacts: @contacts,
count: {
all_count: @contacts.count
}
}
end
def contact_query_builder
contact_filters = @filters['contacts']
@params[:payload].each_with_index do |query_hash, current_index|
current_filter = contact_filters[query_hash['attribute_key']]
@query_string += contact_query_string(current_filter, query_hash, current_index)
end
base_relation.where(@query_string, @filter_values.with_indifferent_access)
end
def contact_query_string(current_filter, query_hash, current_index)
attribute_key = query_hash[:attribute_key]
query_operator = query_hash[:query_operator]
filter_operator_value = filter_operation(query_hash, current_index)
case current_filter['attribute_type']
when 'additional_attributes'
" contacts.additional_attributes ->> '#{attribute_key}' #{filter_operator_value} #{query_operator} "
when 'standard'
if attribute_key == 'labels'
" tags.id #{filter_operator_value} #{query_operator} "
else
" contacts.#{attribute_key} #{filter_operator_value} #{query_operator} "
end
end
end
def base_relation
Current.account.contacts.left_outer_joins(:labels)
end
end

View File

@@ -0,0 +1,59 @@
class Conversations::FilterService < FilterService
def perform
@conversations = conversation_query_builder
mine_count, unassigned_count, all_count, = set_count_for_all_conversations
assigned_count = all_count - unassigned_count
{
conversations: conversations,
count: {
mine_count: mine_count,
assigned_count: assigned_count,
unassigned_count: unassigned_count,
all_count: all_count
}
}
end
def conversation_query_builder
conversation_filters = @filters['conversations']
@params[:payload].each_with_index do |query_hash, current_index|
current_filter = conversation_filters[query_hash['attribute_key']]
@query_string += conversation_query_string(current_filter, query_hash, current_index)
end
base_relation.where(@query_string, @filter_values.with_indifferent_access)
end
def conversation_query_string(current_filter, query_hash, current_index)
attribute_key = query_hash[:attribute_key]
query_operator = query_hash[:query_operator]
filter_operator_value = filter_operation(query_hash, current_index)
case current_filter['attribute_type']
when 'additional_attributes'
" conversations.additional_attributes ->> '#{attribute_key}' #{filter_operator_value} #{query_operator} "
when 'standard'
if attribute_key == 'labels'
" tags.id #{filter_operator_value} #{query_operator} "
else
" conversations.#{attribute_key} #{filter_operator_value} #{query_operator} "
end
end
end
def base_relation
Current.account.conversations.left_outer_joins(:labels)
end
def current_page
@params[:page] || 1
end
def conversations
@conversations = @conversations.includes(
:taggings, :inbox, { assignee: { avatar_attachment: [:blob] } }, { contact: { avatar_attachment: [:blob] } }, :team
)
@conversations.latest.page(current_page)
end
end

View File

@@ -0,0 +1,50 @@
require 'json'
class FilterService
def initialize(params, user)
@params = params
@user = user
file = File.read('./lib/filters/filter_keys.json')
@filters = JSON.parse(file)
@query_string = ''
@filter_values = {}
end
def perform; end
def filter_operation(query_hash, current_index)
case query_hash[:filter_operator]
when 'equal_to'
@filter_values["value_#{current_index}"] = filter_values(query_hash)
"IN (:value_#{current_index})"
when 'not_equal_to'
@filter_values["value_#{current_index}"] = filter_values(query_hash)
"NOT IN (:value_#{current_index})"
when 'contains'
@filter_values["value_#{current_index}"] = "%#{filter_values(query_hash)}%"
"LIKE :value_#{current_index}"
when 'does_not_contain'
@filter_values["value_#{current_index}"] = "%#{filter_values(query_hash)}%"
"NOT LIKE :value_#{current_index}"
else
@filter_values["value_#{current_index}"] = filter_values(query_hash).to_s
"= :value_#{current_index}"
end
end
def filter_values(query_hash)
if query_hash['attribute_key'] == 'status'
query_hash['values'].map { |x| Conversation.statuses[x.to_sym] }
else
query_hash['values']
end
end
def set_count_for_all_conversations
[
@conversations.assigned_to(@user).count,
@conversations.unassigned.count,
@conversations.count
]
end
end

View File

@@ -1,3 +1,10 @@
json.array! @conversations do |conversation|
json.partial! 'api/v1/models/conversation.json.jbuilder', conversation: conversation
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.partial! 'api/v1/conversations/partials/conversation.json.jbuilder', conversation: conversation
end
end