feat: Ability to receive location on whatsapp inbox (#5742)
- Ability to receive location messages on WhatsApp Inbox ref: https://github.com/chatwoot/chatwoot/issues/3398 Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
parent
20406dce01
commit
6ff0c93659
5 changed files with 88 additions and 19 deletions
|
@ -40,6 +40,12 @@
|
||||||
:url="attachment.data_url"
|
:url="attachment.data_url"
|
||||||
:readable-time="readableTime"
|
:readable-time="readableTime"
|
||||||
/>
|
/>
|
||||||
|
<bubble-location
|
||||||
|
v-else-if="attachment.file_type === 'location'"
|
||||||
|
:latitude="attachment.coordinates_lat"
|
||||||
|
:longitude="attachment.coordinates_long"
|
||||||
|
:name="attachment.fallback_title"
|
||||||
|
/>
|
||||||
<bubble-file
|
<bubble-file
|
||||||
v-else
|
v-else
|
||||||
:url="attachment.data_url"
|
:url="attachment.data_url"
|
||||||
|
@ -119,6 +125,7 @@ import BubbleImage from './bubble/Image';
|
||||||
import BubbleFile from './bubble/File';
|
import BubbleFile from './bubble/File';
|
||||||
import BubbleVideo from './bubble/Video.vue';
|
import BubbleVideo from './bubble/Video.vue';
|
||||||
import BubbleActions from './bubble/Actions';
|
import BubbleActions from './bubble/Actions';
|
||||||
|
import BubbleLocation from './bubble/Location';
|
||||||
|
|
||||||
import Spinner from 'shared/components/Spinner';
|
import Spinner from 'shared/components/Spinner';
|
||||||
import ContextMenu from 'dashboard/modules/conversations/components/MessageContextMenu';
|
import ContextMenu from 'dashboard/modules/conversations/components/MessageContextMenu';
|
||||||
|
@ -136,6 +143,7 @@ export default {
|
||||||
BubbleFile,
|
BubbleFile,
|
||||||
BubbleVideo,
|
BubbleVideo,
|
||||||
BubbleMailHead,
|
BubbleMailHead,
|
||||||
|
BubbleLocation,
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
Spinner,
|
Spinner,
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<h5 class="text-block-title text-truncate">
|
<h5 class="text-block-title text-truncate">
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</h5>
|
</h5>
|
||||||
|
<div class="link-wrap">
|
||||||
<a
|
<a
|
||||||
class="download clear link button small"
|
class="download clear link button small"
|
||||||
rel="noreferrer noopener nofollow"
|
rel="noreferrer noopener nofollow"
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -51,23 +53,26 @@ export default {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.icon-wrap {
|
.icon-wrap {
|
||||||
color: var(--white);
|
color: var(--s-600);
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
margin: 0 var(--space-smaller);
|
margin: 0 var(--space-smaller);
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-block-title {
|
.text-block-title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--white);
|
color: var(--s-800);
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.meta {
|
||||||
color: var(--s-25);
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding-right: var(--space-normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
.meta {
|
.link-wrap {
|
||||||
padding-right: var(--space-normal);
|
display: flex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -23,6 +23,7 @@ class Whatsapp::IncomingMessageBaseService
|
||||||
source_id: @processed_params[:messages].first[:id].to_s
|
source_id: @processed_params[:messages].first[:id].to_s
|
||||||
)
|
)
|
||||||
attach_files
|
attach_files
|
||||||
|
attach_location
|
||||||
@message.save!
|
@message.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -78,6 +79,7 @@ class Whatsapp::IncomingMessageBaseService
|
||||||
return :image if %w[image sticker].include?(file_type)
|
return :image if %w[image sticker].include?(file_type)
|
||||||
return :audio if %w[audio voice].include?(file_type)
|
return :audio if %w[audio voice].include?(file_type)
|
||||||
return :video if ['video'].include?(file_type)
|
return :video if ['video'].include?(file_type)
|
||||||
|
return :location if ['location'].include?(file_type)
|
||||||
|
|
||||||
:file
|
:file
|
||||||
end
|
end
|
||||||
|
@ -91,7 +93,7 @@ class Whatsapp::IncomingMessageBaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def attach_files
|
def attach_files
|
||||||
return if %w[text button interactive].include?(message_type)
|
return if %w[text button interactive location].include?(message_type)
|
||||||
|
|
||||||
attachment_payload = @processed_params[:messages].first[message_type.to_sym]
|
attachment_payload = @processed_params[:messages].first[message_type.to_sym]
|
||||||
attachment_file = download_attachment_file(attachment_payload)
|
attachment_file = download_attachment_file(attachment_payload)
|
||||||
|
@ -111,4 +113,19 @@ class Whatsapp::IncomingMessageBaseService
|
||||||
def download_attachment_file(attachment_payload)
|
def download_attachment_file(attachment_payload)
|
||||||
Down.download(inbox.channel.media_url(attachment_payload[:id]), headers: inbox.channel.api_headers)
|
Down.download(inbox.channel.media_url(attachment_payload[:id]), headers: inbox.channel.api_headers)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def attach_location
|
||||||
|
return unless @processed_params[:messages].first[:type] == 'location'
|
||||||
|
|
||||||
|
location = @processed_params[:messages].first['location']
|
||||||
|
location_name = location['name'] ? "#{location['name']}, #{location['address']}" : ''
|
||||||
|
@message.attachments.new(
|
||||||
|
account_id: @message.account_id,
|
||||||
|
file_type: file_content_type(message_type),
|
||||||
|
coordinates_lat: location['latitude'],
|
||||||
|
coordinates_long: location['longitude'],
|
||||||
|
fallback_title: location_name,
|
||||||
|
external_url: location['url']
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
16
db/seeds.rb
16
db/seeds.rb
|
@ -66,7 +66,21 @@ unless Rails.env.production?
|
||||||
# sample email collect
|
# sample email collect
|
||||||
Seeders::MessageSeeder.create_sample_email_collect_message conversation
|
Seeders::MessageSeeder.create_sample_email_collect_message conversation
|
||||||
|
|
||||||
Message.create!(content: 'Hello', account: account, inbox: inbox, conversation: conversation, message_type: :incoming)
|
Message.create!(content: 'Hello', account: account, inbox: inbox, conversation: conversation, sender: contact_inbox.contact,
|
||||||
|
message_type: :incoming)
|
||||||
|
|
||||||
|
# sample location message
|
||||||
|
#
|
||||||
|
location_message = Message.new(content: 'location', account: account, inbox: inbox, sender: contact_inbox.contact, conversation: conversation,
|
||||||
|
message_type: :incoming)
|
||||||
|
location_message.attachments.new(
|
||||||
|
account_id: account.id,
|
||||||
|
file_type: 'location',
|
||||||
|
coordinates_lat: 37.7893768,
|
||||||
|
coordinates_long: -122.3895553,
|
||||||
|
fallback_title: 'Bay Bridge, San Francisco, CA, USA'
|
||||||
|
)
|
||||||
|
location_message.save!
|
||||||
|
|
||||||
# sample card
|
# sample card
|
||||||
Seeders::MessageSeeder.create_sample_cards_message conversation
|
Seeders::MessageSeeder.create_sample_cards_message conversation
|
||||||
|
|
|
@ -39,8 +39,8 @@ describe Whatsapp::IncomingMessageService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when ignores the message' do
|
context 'when unsupported message types' do
|
||||||
it 'with message type is ephemeral' do
|
it 'ignores type ephemeral' do
|
||||||
params = {
|
params = {
|
||||||
'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => '2423423243' }],
|
'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => '2423423243' }],
|
||||||
'messages' => [{ 'from' => '2423423243', 'id' => 'SDFADSf23sfasdafasdfa', 'text' => { 'body' => 'Test' },
|
'messages' => [{ 'from' => '2423423243', 'id' => 'SDFADSf23sfasdafasdfa', 'text' => { 'body' => 'Test' },
|
||||||
|
@ -53,7 +53,7 @@ describe Whatsapp::IncomingMessageService do
|
||||||
expect(whatsapp_channel.inbox.messages.count).to eq(0)
|
expect(whatsapp_channel.inbox.messages.count).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'with message type is unsupported' do
|
it 'ignores type unsupported' do
|
||||||
params = {
|
params = {
|
||||||
'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => '2423423243' }],
|
'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => '2423423243' }],
|
||||||
'messages' => [{
|
'messages' => [{
|
||||||
|
@ -132,5 +132,30 @@ describe Whatsapp::IncomingMessageService do
|
||||||
expect(whatsapp_channel.inbox.messages.first.attachments.present?).to be true
|
expect(whatsapp_channel.inbox.messages.first.attachments.present?).to be true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when valid location message params' do
|
||||||
|
it 'creates appropriate conversations, message and contacts' do
|
||||||
|
params = {
|
||||||
|
'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => '2423423243' }],
|
||||||
|
'messages' => [{ 'from' => '2423423243', 'id' => 'SDFADSf23sfasdafasdfa',
|
||||||
|
'location' => { 'id' => 'b1c68f38-8734-4ad3-b4a1-ef0c10d683',
|
||||||
|
'address': 'San Francisco, CA, USA',
|
||||||
|
'latitude': 37.7893768,
|
||||||
|
'longitude': -122.3895553,
|
||||||
|
'name': 'Bay Bridge',
|
||||||
|
'url': 'http://location_url.test' },
|
||||||
|
'timestamp' => '1633034394', 'type' => 'location' }]
|
||||||
|
}.with_indifferent_access
|
||||||
|
described_class.new(inbox: whatsapp_channel.inbox, params: params).perform
|
||||||
|
expect(whatsapp_channel.inbox.conversations.count).not_to eq(0)
|
||||||
|
expect(Contact.all.first.name).to eq('Sojan Jose')
|
||||||
|
location_attachment = whatsapp_channel.inbox.messages.first.attachments.first
|
||||||
|
expect(location_attachment.file_type).to eq('location')
|
||||||
|
expect(location_attachment.fallback_title).to eq('Bay Bridge, San Francisco, CA, USA')
|
||||||
|
expect(location_attachment.coordinates_lat).to eq(37.7893768)
|
||||||
|
expect(location_attachment.coordinates_long).to eq(-122.3895553)
|
||||||
|
expect(location_attachment.external_url).to eq('http://location_url.test')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue