mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 12:08:01 +00:00
feat: Slack link unfurling (#7940)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
class Integrations::Slack::IncomingMessageBuilder
|
||||
include Integrations::Slack::SlackMessageHelper
|
||||
|
||||
attr_reader :params
|
||||
|
||||
SUPPORTED_EVENT_TYPES = %w[event_callback url_verification].freeze
|
||||
SUPPORTED_EVENTS = %w[message].freeze
|
||||
SUPPORTED_EVENTS = %w[message link_shared].freeze
|
||||
SUPPORTED_MESSAGE_TYPES = %w[rich_text].freeze
|
||||
|
||||
def initialize(params)
|
||||
@@ -17,6 +18,8 @@ class Integrations::Slack::IncomingMessageBuilder
|
||||
verify_hook
|
||||
elsif create_message?
|
||||
create_message
|
||||
elsif link_shared?
|
||||
SlackUnfurlJob.perform_later(params, integration_hook)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -68,6 +71,10 @@ class Integrations::Slack::IncomingMessageBuilder
|
||||
thread_timestamp_available? && supported_message? && integration_hook
|
||||
end
|
||||
|
||||
def link_shared?
|
||||
params[:event][:type] == 'link_shared' && integration_hook
|
||||
end
|
||||
|
||||
def message
|
||||
params[:event][:blocks]&.first
|
||||
end
|
||||
@@ -82,19 +89,6 @@ class Integrations::Slack::IncomingMessageBuilder
|
||||
@integration_hook ||= Integrations::Hook.find_by(reference_id: params[:event][:channel])
|
||||
end
|
||||
|
||||
def conversation
|
||||
@conversation ||= Conversation.where(identifier: params[:event][:thread_ts]).first
|
||||
end
|
||||
|
||||
def sender
|
||||
user_email = slack_client.users_info(user: params[:event][:user])[:user][:profile][:email]
|
||||
conversation.account.users.find_by(email: user_email)
|
||||
end
|
||||
|
||||
def private_note?
|
||||
params[:event][:text].strip.downcase.starts_with?('note:', 'private:')
|
||||
end
|
||||
|
||||
def slack_client
|
||||
@slack_client ||= Slack::Web::Client.new(token: @integration_hook.access_token)
|
||||
end
|
||||
|
||||
59
lib/integrations/slack/link_unfurl_formatter.rb
Normal file
59
lib/integrations/slack/link_unfurl_formatter.rb
Normal file
@@ -0,0 +1,59 @@
|
||||
class Integrations::Slack::LinkUnfurlFormatter
|
||||
pattr_initialize [:url!, :user_info!, :inbox_name!, :inbox_type!]
|
||||
|
||||
def perform
|
||||
return {} if url.blank?
|
||||
|
||||
{
|
||||
url => {
|
||||
'blocks' => preivew_blocks(user_info) +
|
||||
open_conversation_button(url)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def preivew_blocks(user_info)
|
||||
[
|
||||
{
|
||||
'type' => 'section',
|
||||
'fields' => [
|
||||
preview_field(I18n.t('slack_unfurl.fields.name'), user_info[:user_name]),
|
||||
preview_field(I18n.t('slack_unfurl.fields.email'), user_info[:email]),
|
||||
preview_field(I18n.t('slack_unfurl.fields.phone_number'), user_info[:phone_number]),
|
||||
preview_field(I18n.t('slack_unfurl.fields.company_name'), user_info[:company_name]),
|
||||
preview_field(I18n.t('slack_unfurl.fields.inbox_name'), inbox_name),
|
||||
preview_field(I18n.t('slack_unfurl.fields.inbox_type'), inbox_type)
|
||||
]
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
def preview_field(label, value)
|
||||
{
|
||||
'type' => 'mrkdwn',
|
||||
'text' => "*#{label}:*\n#{value}"
|
||||
}
|
||||
end
|
||||
|
||||
def open_conversation_button(url)
|
||||
[
|
||||
{
|
||||
'type' => 'actions',
|
||||
'elements' => [
|
||||
{
|
||||
'type' => 'button',
|
||||
'text' => {
|
||||
'type' => 'plain_text',
|
||||
'text' => I18n.t('slack_unfurl.button'),
|
||||
'emoji' => true
|
||||
},
|
||||
'url' => url,
|
||||
'action_id' => 'button-action'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
@@ -14,6 +14,12 @@ class Integrations::Slack::SendOnSlackService < Base::SendOnChannelService
|
||||
perform_reply
|
||||
end
|
||||
|
||||
def link_unfurl(event)
|
||||
slack_client.chat_unfurl(
|
||||
event
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def valid_channel_for_slack?
|
||||
|
||||
84
lib/integrations/slack/slack_link_unfurl_service.rb
Normal file
84
lib/integrations/slack/slack_link_unfurl_service.rb
Normal file
@@ -0,0 +1,84 @@
|
||||
class Integrations::Slack::SlackLinkUnfurlService
|
||||
pattr_initialize [:params!, :integration_hook!]
|
||||
|
||||
def perform
|
||||
event_links = params.dig(:event, :links)
|
||||
return unless event_links
|
||||
|
||||
event_links.each do |link_info|
|
||||
url = link_info[:url]
|
||||
# Unfurl only if the account id is same as the integration hook account id
|
||||
unfurl_link(url) if url && valid_account?(url)
|
||||
end
|
||||
end
|
||||
|
||||
def unfurl_link(url)
|
||||
conversation = conversation_from_url(url)
|
||||
return unless conversation
|
||||
|
||||
send_unfurls(url, conversation)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def contact_attributes(conversation)
|
||||
contact = conversation.contact
|
||||
{
|
||||
user_name: contact.name.presence || '---',
|
||||
email: contact.email.presence || '---',
|
||||
phone_number: contact.phone_number.presence || '---',
|
||||
company_name: contact.additional_attributes&.dig('company_name').presence || '---'
|
||||
}
|
||||
end
|
||||
|
||||
def generate_unfurls(url, user_info, inbox)
|
||||
Integrations::Slack::LinkUnfurlFormatter.new(
|
||||
url: url,
|
||||
user_info: user_info,
|
||||
inbox_name: inbox.name,
|
||||
inbox_type: inbox.channel.name
|
||||
).perform
|
||||
end
|
||||
|
||||
def send_unfurls(url, conversation)
|
||||
user_info = contact_attributes(conversation)
|
||||
unfurls = generate_unfurls(url, user_info, conversation.inbox)
|
||||
unfurl_params = {
|
||||
unfurl_id: params.dig(:event, :unfurl_id),
|
||||
source: params.dig(:event, :source),
|
||||
unfurls: JSON.generate(unfurls)
|
||||
}
|
||||
|
||||
slack_service = Integrations::Slack::SendOnSlackService.new(
|
||||
message: nil,
|
||||
hook: integration_hook
|
||||
)
|
||||
slack_service.link_unfurl(unfurl_params)
|
||||
end
|
||||
|
||||
def conversation_from_url(url)
|
||||
conversation_id = extract_conversation_id(url)
|
||||
find_conversation_by_id(conversation_id) if conversation_id
|
||||
end
|
||||
|
||||
def find_conversation_by_id(conversation_id)
|
||||
Conversation.find_by(display_id: conversation_id, account_id: integration_hook.account_id)
|
||||
end
|
||||
|
||||
def valid_account?(url)
|
||||
account_id = extract_account_id(url)
|
||||
account_id == integration_hook.account_id.to_s
|
||||
end
|
||||
|
||||
def extract_account_id(url)
|
||||
account_id_regex = %r{/accounts/(\d+)}
|
||||
match_data = url.match(account_id_regex)
|
||||
match_data[1] if match_data
|
||||
end
|
||||
|
||||
def extract_conversation_id(url)
|
||||
conversation_id_regex = %r{/conversations/(\d+)}
|
||||
match_data = url.match(conversation_id_regex)
|
||||
match_data[1] if match_data
|
||||
end
|
||||
end
|
||||
@@ -62,4 +62,17 @@ module Integrations::Slack::SlackMessageHelper
|
||||
:file
|
||||
end
|
||||
end
|
||||
|
||||
def conversation
|
||||
@conversation ||= Conversation.where(identifier: params[:event][:thread_ts]).first
|
||||
end
|
||||
|
||||
def sender
|
||||
user_email = slack_client.users_info(user: params[:event][:user])[:user][:profile][:email]
|
||||
conversation.account.users.find_by(email: user_email)
|
||||
end
|
||||
|
||||
def private_note?
|
||||
params[:event][:text].strip.downcase.starts_with?('note:', 'private:')
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user