mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 11:37:58 +00:00
feat: Show shared contact's name in Telegram channel (#10856)
# Pull Request Template ## Description This PR adds the ability to see the shared contact name in Telegram channels. ## Type of change - [x] New feature (non-breaking change which adds functionality) ## How Has This Been Tested? **Loom video** https://www.loom.com/share/cd318056ad4d44d4a1fc4b5d4ad38d60?sid=26d833ae-ded9-4cf0-9af7-81eecfa37f19 ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
This commit is contained in:
@@ -10,6 +10,7 @@ defineProps({
|
|||||||
iconBgColor: { type: String, default: 'bg-n-alpha-3' },
|
iconBgColor: { type: String, default: 'bg-n-alpha-3' },
|
||||||
senderTranslationKey: { type: String, required: true },
|
senderTranslationKey: { type: String, required: true },
|
||||||
content: { type: String, required: true },
|
content: { type: String, required: true },
|
||||||
|
title: { type: String, default: '' }, // Title can be any name, description, etc
|
||||||
action: {
|
action: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
@@ -48,6 +49,9 @@ const senderName = computed(() => {
|
|||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
<slot>
|
<slot>
|
||||||
|
<div v-if="title" class="truncate text-sm text-n-slate-12">
|
||||||
|
{{ title }}
|
||||||
|
</div>
|
||||||
<div v-if="content" class="truncate text-sm text-n-slate-11">
|
<div v-if="content" class="truncate text-sm text-n-slate-11">
|
||||||
{{ content }}
|
{{ content }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
ExceptionWithMessage,
|
ExceptionWithMessage,
|
||||||
} from 'shared/helpers/CustomErrors';
|
} from 'shared/helpers/CustomErrors';
|
||||||
|
|
||||||
const { content, attachments } = useMessageContext();
|
const { attachments } = useMessageContext();
|
||||||
|
|
||||||
const $store = useStore();
|
const $store = useStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@@ -24,6 +24,12 @@ const phoneNumber = computed(() => {
|
|||||||
return attachment.value.fallbackTitle;
|
return attachment.value.fallbackTitle;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const contactName = computed(() => {
|
||||||
|
const { meta } = attachment.value ?? {};
|
||||||
|
const { firstName, lastName } = meta ?? {};
|
||||||
|
return `${firstName ?? ''} ${lastName ?? ''}`.trim();
|
||||||
|
});
|
||||||
|
|
||||||
const formattedPhoneNumber = computed(() => {
|
const formattedPhoneNumber = computed(() => {
|
||||||
return phoneNumber.value.replace(/\s|-|[A-Za-z]/g, '');
|
return phoneNumber.value.replace(/\s|-|[A-Za-z]/g, '');
|
||||||
});
|
});
|
||||||
@@ -32,13 +38,9 @@ const rawPhoneNumber = computed(() => {
|
|||||||
return phoneNumber.value.replace(/\D/g, '');
|
return phoneNumber.value.replace(/\D/g, '');
|
||||||
});
|
});
|
||||||
|
|
||||||
const name = computed(() => {
|
|
||||||
return content.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
function getContactObject() {
|
function getContactObject() {
|
||||||
const contactItem = {
|
const contactItem = {
|
||||||
name: name.value,
|
name: contactName.value,
|
||||||
phone_number: `+${rawPhoneNumber.value}`,
|
phone_number: `+${rawPhoneNumber.value}`,
|
||||||
};
|
};
|
||||||
return contactItem;
|
return contactItem;
|
||||||
@@ -99,6 +101,7 @@ const action = computed(() => ({
|
|||||||
icon="i-teenyicons-user-circle-solid"
|
icon="i-teenyicons-user-circle-solid"
|
||||||
icon-bg-color="bg-[#D6409F]"
|
icon-bg-color="bg-[#D6409F]"
|
||||||
sender-translation-key="CONVERSATION.SHARED_ATTACHMENT.CONTACT"
|
sender-translation-key="CONVERSATION.SHARED_ATTACHMENT.CONTACT"
|
||||||
|
:title="contactName"
|
||||||
:content="phoneNumber"
|
:content="phoneNumber"
|
||||||
:action="formattedPhoneNumber ? action : null"
|
:action="formattedPhoneNumber ? action : null"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
# external_url :string
|
# external_url :string
|
||||||
# fallback_title :string
|
# fallback_title :string
|
||||||
# file_type :integer default("image")
|
# file_type :integer default("image")
|
||||||
|
# meta :jsonb
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
# account_id :integer not null
|
# account_id :integer not null
|
||||||
@@ -116,7 +117,8 @@ class Attachment < ApplicationRecord
|
|||||||
|
|
||||||
def contact_metadata
|
def contact_metadata
|
||||||
{
|
{
|
||||||
fallback_title: fallback_title
|
fallback_title: fallback_title,
|
||||||
|
meta: meta || {}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,11 @@ class Telegram::IncomingMessageService
|
|||||||
@message.attachments.new(
|
@message.attachments.new(
|
||||||
account_id: @message.account_id,
|
account_id: @message.account_id,
|
||||||
file_type: :contact,
|
file_type: :contact,
|
||||||
fallback_title: contact_card['phone_number'].to_s
|
fallback_title: contact_card['phone_number'].to_s,
|
||||||
|
meta: {
|
||||||
|
first_name: contact_card['first_name'],
|
||||||
|
last_name: contact_card['last_name']
|
||||||
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
5
db/migrate/20250207040150_add_meta_to_attachment.rb
Normal file
5
db/migrate/20250207040150_add_meta_to_attachment.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class AddMetaToAttachment < ActiveRecord::Migration[7.0]
|
||||||
|
def change
|
||||||
|
add_column :attachments, :meta, :jsonb, default: {}
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.0].define(version: 2025_01_16_061033) do
|
ActiveRecord::Schema[7.0].define(version: 2025_02_07_040150) do
|
||||||
# These extensions should be enabled to support this database
|
# These extensions should be enabled to support this database
|
||||||
enable_extension "pg_stat_statements"
|
enable_extension "pg_stat_statements"
|
||||||
enable_extension "pg_trgm"
|
enable_extension "pg_trgm"
|
||||||
@@ -174,6 +174,7 @@ ActiveRecord::Schema[7.0].define(version: 2025_01_16_061033) do
|
|||||||
t.datetime "updated_at", precision: nil, null: false
|
t.datetime "updated_at", precision: nil, null: false
|
||||||
t.string "fallback_title"
|
t.string "fallback_title"
|
||||||
t.string "extension"
|
t.string "extension"
|
||||||
|
t.jsonb "meta", default: {}
|
||||||
t.index ["account_id"], name: "index_attachments_on_account_id"
|
t.index ["account_id"], name: "index_attachments_on_account_id"
|
||||||
t.index ["message_id"], name: "index_attachments_on_message_id"
|
t.index ["message_id"], name: "index_attachments_on_message_id"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -67,4 +67,65 @@ RSpec.describe Attachment do
|
|||||||
expect(message.attachments.first.push_event_data[:data_url]).not_to eq message.attachments.first.external_url
|
expect(message.attachments.first.push_event_data[:data_url]).not_to eq message.attachments.first.external_url
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'meta data handling' do
|
||||||
|
let(:message) { create(:message) }
|
||||||
|
|
||||||
|
context 'when attachment is a contact type' do
|
||||||
|
let(:contact_attachment) do
|
||||||
|
message.attachments.create!(
|
||||||
|
account_id: message.account_id,
|
||||||
|
file_type: :contact,
|
||||||
|
fallback_title: '+1234567890',
|
||||||
|
meta: {
|
||||||
|
first_name: 'John',
|
||||||
|
last_name: 'Doe'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'stores and retrieves meta data correctly' do
|
||||||
|
expect(contact_attachment.meta['first_name']).to eq('John')
|
||||||
|
expect(contact_attachment.meta['last_name']).to eq('Doe')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'includes meta data in push_event_data' do
|
||||||
|
event_data = contact_attachment.push_event_data
|
||||||
|
expect(event_data[:meta]).to eq({
|
||||||
|
'first_name' => 'John',
|
||||||
|
'last_name' => 'Doe'
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns empty hash for meta if not set' do
|
||||||
|
attachment = message.attachments.create!(
|
||||||
|
account_id: message.account_id,
|
||||||
|
file_type: :contact,
|
||||||
|
fallback_title: '+1234567890'
|
||||||
|
)
|
||||||
|
expect(attachment.push_event_data[:meta]).to eq({})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when meta is used with other file types' do
|
||||||
|
let(:image_attachment) do
|
||||||
|
attachment = message.attachments.new(
|
||||||
|
account_id: message.account_id,
|
||||||
|
file_type: :image,
|
||||||
|
meta: { description: 'Test image' }
|
||||||
|
)
|
||||||
|
attachment.file.attach(
|
||||||
|
io: Rails.root.join('spec/assets/avatar.png').open,
|
||||||
|
filename: 'avatar.png',
|
||||||
|
content_type: 'image/png'
|
||||||
|
)
|
||||||
|
attachment.save!
|
||||||
|
attachment
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'preserves meta data with file attachments' do
|
||||||
|
expect(image_attachment.meta['description']).to eq('Test image')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user