feat: Add Public APIs for API Channel (#2375)

This commit is contained in:
Sojan Jose
2021-06-15 20:09:17 +05:30
committed by GitHub
parent 0f377da109
commit 853db60f8e
29 changed files with 404 additions and 11 deletions

View File

@@ -1,5 +1,5 @@
class ContactBuilder
pattr_initialize [:source_id!, :inbox!, :contact_attributes!]
pattr_initialize [:source_id!, :inbox!, :contact_attributes!, :hmac_verified]
def perform
contact_inbox = inbox.contact_inboxes.find_by(source_id: source_id)
@@ -18,7 +18,8 @@ class ContactBuilder
::ContactInbox.create!(
contact_id: contact.id,
inbox_id: inbox.id,
source_id: source_id
source_id: source_id,
hmac_verified: hmac_verified || false
)
end
@@ -28,7 +29,7 @@ class ContactBuilder
def create_contact
account.contacts.create!(
name: contact_attributes[:name],
name: contact_attributes[:name] || ::Haikunator.haikunate(1000),
phone_number: contact_attributes[:phone_number],
email: contact_attributes[:email],
identifier: contact_attributes[:identifier],

View File

@@ -58,6 +58,7 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
end
def permitted_params
# timestamp parameter is used in create conversation method
params.permit(:id, :before, :website_token, contact: [:name, :email], message: [:content, :referer_url, :timestamp, :echo_id])
end

View File

@@ -0,0 +1,48 @@
class Public::Api::V1::Inboxes::ContactsController < Public::Api::V1::InboxesController
before_action :contact_inbox, except: [:create]
before_action :process_hmac
def create
source_id = params[:source_id] || SecureRandom.uuid
@contact_inbox = ::ContactBuilder.new(
source_id: source_id,
inbox: @inbox_channel.inbox,
contact_attributes: permitted_params.except(:identifier, :identifier_hash)
).perform
end
def show; end
def update
contact_identify_action = ContactIdentifyAction.new(
contact: @contact_inbox.contact,
params: permitted_params.to_h.deep_symbolize_keys.except(:identifier)
)
render json: contact_identify_action.perform
end
private
def contact_inbox
@contact_inbox = @inbox_channel.inbox.contact_inboxes.find_by!(source_id: params[:id])
end
def process_hmac
return if params[:identifier_hash].blank? && !@inbox_channel.hmac_mandatory
raise StandardError, 'HMAC failed: Invalid Identifier Hash Provided' unless valid_hmac?
@contact_inbox.update(hmac_verified: true) if @contact_inbox.present?
end
def valid_hmac?
params[:identifier_hash] == OpenSSL::HMAC.hexdigest(
'sha256',
@inbox_channel.hmac_token,
params[:identifier].to_s
)
end
def permitted_params
params.permit(:identifier, :identifier_hash, :email, :name, :avatar_url, custom_attributes: {})
end
end

View File

@@ -0,0 +1,24 @@
class Public::Api::V1::Inboxes::ConversationsController < Public::Api::V1::InboxesController
def index
@conversations = @contact_inbox.hmac_verified? ? @contact.conversations : @contact_inbox.conversations
end
def create
@conversation = create_conversation
end
private
def create_conversation
::Conversation.create!(conversation_params)
end
def conversation_params
{
account_id: @contact_inbox.contact.account_id,
inbox_id: @contact_inbox.inbox_id,
contact_id: @contact_inbox.contact_id,
contact_inbox_id: @contact_inbox.id
}
end
end

View File

@@ -0,0 +1,68 @@
class Public::Api::V1::Inboxes::MessagesController < Public::Api::V1::InboxesController
before_action :set_message, only: [:update]
def index
@messages = @conversation.nil? ? [] : message_finder.perform
end
def create
@message = @conversation.messages.new(message_params)
@message.save
build_attachment
end
def update
@message.update!(message_update_params)
rescue StandardError => e
render json: { error: @contact.errors, message: e.message }.to_json, status: 500
end
private
def build_attachment
return if params[:attachments].blank?
params[:attachments].each do |uploaded_attachment|
attachment = @message.attachments.new(
account_id: @message.account_id,
file_type: helpers.file_type(uploaded_attachment&.content_type)
)
attachment.file.attach(uploaded_attachment)
end
@message.save!
end
def message_finder_params
{
filter_internal_messages: true,
before: params[:before]
}
end
def message_finder
@message_finder ||= MessageFinder.new(@conversation, message_finder_params)
end
def message_update_params
params.permit(submitted_values: [:name, :title, :value])
end
def permitted_params
params.permit(:content, :echo_id)
end
def set_message
@message = @conversation.messages.find(params[:id])
end
def message_params
{
account_id: @conversation.account_id,
sender: @contact_inbox.contact,
content: permitted_params[:content],
inbox_id: @conversation.inbox_id,
echo_id: permitted_params[:echo_id],
message_type: :incoming
}
end
end

View File

@@ -0,0 +1,23 @@
class Public::Api::V1::InboxesController < PublicController
before_action :set_inbox_channel
before_action :set_contact_inbox
before_action :set_conversation
private
def set_inbox_channel
@inbox_channel = ::Channel::Api.find_by!(identifier: params[:inbox_id])
end
def set_contact_inbox
return if params[:contact_id].blank?
@contact_inbox = @inbox_channel.inbox.contact_inboxes.find_by!(source_id: params[:contact_id])
end
def set_conversation
return if params[:conversation_id].blank?
@conversation = @contact_inbox.contact.conversations.find_by!(display_id: params[:conversation_id])
end
end

View File

@@ -0,0 +1,3 @@
class PublicController < ActionController::Base
skip_before_action :verify_authenticity_token
end

View File

@@ -2,11 +2,19 @@
#
# Table name: channel_api
#
# id :bigint not null, primary key
# webhook_url :string
# created_at :datetime not null
# updated_at :datetime not null
# account_id :integer not null
# id :bigint not null, primary key
# hmac_mandatory :boolean default(FALSE)
# hmac_token :string
# identifier :string
# webhook_url :string
# created_at :datetime not null
# updated_at :datetime not null
# account_id :integer not null
#
# Indexes
#
# index_channel_api_on_hmac_token (hmac_token) UNIQUE
# index_channel_api_on_identifier (identifier) UNIQUE
#
class Channel::Api < ApplicationRecord
@@ -15,6 +23,9 @@ class Channel::Api < ApplicationRecord
validates :account_id, presence: true
belongs_to :account
has_secure_token :identifier
has_secure_token :hmac_token
has_one :inbox, as: :channel, dependent: :destroy
def name

View File

@@ -4,6 +4,7 @@
#
# id :integer not null, primary key
# feature_flags :integer default(3), not null
# hmac_mandatory :boolean default(FALSE)
# hmac_token :string
# pre_chat_form_enabled :boolean default(FALSE)
# pre_chat_form_options :jsonb

View File

@@ -0,0 +1,2 @@
json.source_id @contact_inbox.source_id
json.partial! 'public/api/v1/models/contact.json.jbuilder', resource: @contact_inbox.contact

View File

@@ -0,0 +1,2 @@
json.source_id @contact_inbox.source_id
json.partial! 'public/api/v1/models/contact.json.jbuilder', resource: @contact_inbox.contact

View File

@@ -0,0 +1,2 @@
json.source_id @contact_inbox.source_id
json.partial! 'public/api/v1/models/contact.json.jbuilder', resource: @contact_inbox.contact

View File

@@ -0,0 +1 @@
json.partial! 'public/api/v1/models/conversation.json.jbuilder', resource: @conversation

View File

@@ -0,0 +1,3 @@
json.array! @conversations do |conversation|
json.partial! 'public/api/v1/models/conversation.json.jbuilder', resource: conversation
end

View File

@@ -0,0 +1 @@
json.partial! 'public/api/v1/models/message.json.jbuilder', resource: @message

View File

@@ -0,0 +1,3 @@
json.array! @messages do |message|
json.partial! 'public/api/v1/models/message.json.jbuilder', resource: message
end

View File

@@ -0,0 +1 @@
json.partial! 'public/api/v1/models/message.json.jbuilder', resource: @message

View File

@@ -0,0 +1,4 @@
json.id resource.id
json.name resource.name
json.email resource.email
json.pubsub_token resource.pubsub_token

View File

@@ -0,0 +1,10 @@
json.id resource.display_id
json.inbox_id resource.inbox_id
json.contact_last_seen_at resource.contact_last_seen_at.to_i
json.status resource.status
json.messages do
json.array! resource.messages do |message|
json.partial! 'public/api/v1/models/message.json.jbuilder', resource: message
end
end
json.contact resource.contact

View File

@@ -0,0 +1,9 @@
json.id resource.id
json.content resource.content
json.message_type resource.message_type_before_type_cast
json.content_type resource.content_type
json.content_attributes resource.content_attributes
json.created_at resource.created_at.to_i
json.conversation_id resource.conversation.display_id
json.attachments resource.attachments.map(&:push_event_data) if resource.attachments.present?
json.sender resource.sender.push_event_data if resource.sender