feat: do not send contact details to the widget (#9223)

* refactor: use has_email instead of email

* feat: remove usage of details directly in forms

* test: update payload

* test: fix transcript test

* refactor: use computed hasEmail

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
Shivam Mishra
2024-04-12 15:30:07 +05:30
committed by GitHub
parent dc757598f1
commit bce2a07d03
11 changed files with 70 additions and 37 deletions

View File

@@ -33,10 +33,10 @@ class Api::V1::Widget::ConversationsController < Api::V1::Widget::BaseController
end end
def transcript def transcript
if permitted_params[:email].present? && conversation.present? if conversation.present? && conversation.contact.present? && conversation.contact.email.present?
ConversationReplyMailer.with(account: conversation.account).conversation_transcript( ConversationReplyMailer.with(account: conversation.account).conversation_transcript(
conversation, conversation,
permitted_params[:email] conversation.contact.email
)&.deliver_later )&.deliver_later
end end
head :ok head :ok

View File

@@ -38,10 +38,9 @@ const setUserLastSeenAt = async ({ lastSeen }) => {
{ contact_last_seen_at: lastSeen } { contact_last_seen_at: lastSeen }
); );
}; };
const sendEmailTranscript = async ({ email }) => { const sendEmailTranscript = async () => {
return API.post( return API.post(
`/api/v1/widget/conversations/transcript${window.location.search}`, `/api/v1/widget/conversations/transcript${window.location.search}`
{ email }
); );
}; };
const toggleStatus = async () => { const toggleStatus = async () => {

View File

@@ -87,7 +87,10 @@ export default {
return !allowMessagesAfterResolved && status === 'resolved'; return !allowMessagesAfterResolved && status === 'resolved';
}, },
showEmailTranscriptButton() { showEmailTranscriptButton() {
return this.currentUser && this.currentUser.email; return this.hasEmail;
},
hasEmail() {
return this.currentUser && this.currentUser.has_email;
}, },
hasReplyTo() { hasReplyTo() {
return ( return (
@@ -141,12 +144,9 @@ export default {
this.inReplyTo = message; this.inReplyTo = message;
}, },
async sendTranscript() { async sendTranscript() {
const { email } = this.currentUser; if (this.hasEmail) {
if (email) {
try { try {
await sendEmailTranscript({ await sendEmailTranscript();
email,
});
window.bus.$emit(BUS_EVENTS.SHOW_ALERT, { window.bus.$emit(BUS_EVENTS.SHOW_ALERT, {
message: this.$t('EMAIL_TRANSCRIPT.SEND_EMAIL_SUCCESS'), message: this.$t('EMAIL_TRANSCRIPT.SEND_EMAIL_SUCCESS'),
type: 'success', type: 'success',

View File

@@ -1,7 +1,7 @@
<template> <template>
<FormulateForm <FormulateForm
v-model="formValues" v-model="formValues"
class="flex flex-1 flex-col p-6 overflow-y-auto" class="flex flex-col flex-1 p-6 overflow-y-auto"
@submit="onSubmit" @submit="onSubmit"
> >
<div <div
@@ -49,7 +49,7 @@
/> />
<custom-button <custom-button
class="font-medium mt-2 mb-5" class="mt-2 mb-5 font-medium"
block block
:bg-color="widgetColor" :bg-color="widgetColor"
:text-color="textColor" :text-color="textColor"
@@ -133,9 +133,10 @@ export default {
return this.preChatFormEnabled ? this.options.preChatFields : []; return this.preChatFormEnabled ? this.options.preChatFields : [];
}, },
filteredPreChatFields() { filteredPreChatFields() {
const isUserEmailAvailable = !!this.currentUser.email; const isUserEmailAvailable = this.currentUser.has_email;
const isUserPhoneNumberAvailable = !!this.currentUser.phone_number; const isUserPhoneNumberAvailable = this.currentUser.has_phone_number;
const isUserIdentifierAvailable = !!this.currentUser.identifier; const isUserIdentifierAvailable = !!this.currentUser.identifier;
const isUserNameAvailable = !!( const isUserNameAvailable = !!(
isUserIdentifierAvailable || isUserIdentifierAvailable ||
isUserEmailAvailable || isUserEmailAvailable ||
@@ -302,11 +303,10 @@ export default {
}, },
onSubmit() { onSubmit() {
const { emailAddress, fullName, phoneNumber, message } = this.formValues; const { emailAddress, fullName, phoneNumber, message } = this.formValues;
const { email } = this.currentUser;
this.$emit('submit', { this.$emit('submit', {
fullName, fullName,
phoneNumber, phoneNumber,
emailAddress: emailAddress || email, emailAddress,
message, message,
activeCampaignId: this.activeCampaign.id, activeCampaignId: this.activeCampaign.id,
conversationCustomAttributes: this.conversationCustomAttributes, conversationCustomAttributes: this.conversationCustomAttributes,

View File

@@ -3,8 +3,8 @@ import { getters } from '../../contacts';
describe('#getters', () => { describe('#getters', () => {
it('getCurrentUser', () => { it('getCurrentUser', () => {
const user = { const user = {
email: 'thoma@sphadikam.com', has_email: true,
name: 'Adu Thoma', has_name: true,
avatar_url: '', avatar_url: '',
identifier_hash: 'malana_hash', identifier_hash: 'malana_hash',
}; };
@@ -12,8 +12,8 @@ describe('#getters', () => {
currentUser: user, currentUser: user,
}; };
expect(getters.getCurrentUser(state)).toEqual({ expect(getters.getCurrentUser(state)).toEqual({
email: 'thoma@sphadikam.com', has_email: true,
name: 'Adu Thoma', has_name: true,
avatar_url: '', avatar_url: '',
identifier_hash: 'malana_hash', identifier_hash: 'malana_hash',
}); });

View File

@@ -4,8 +4,8 @@ describe('#mutations', () => {
describe('#SET_CURRENT_USER', () => { describe('#SET_CURRENT_USER', () => {
it('set current user', () => { it('set current user', () => {
const user = { const user = {
email: 'thoma@sphadikam.com', has_email: true,
name: 'Adu Thoma', has_name: true,
avatar_url: '', avatar_url: '',
identifier_hash: 'malana_hash', identifier_hash: 'malana_hash',
}; };

View File

@@ -1,5 +1,5 @@
json.id @contact.id json.id @contact.id
json.name @contact.name json.has_email @contact.email.present?
json.email @contact.email json.has_name @contact.name.present?
json.phone_number @contact.phone_number json.has_phone_number @contact.phone_number.present?
json.widget_auth_token @widget_auth_token if @widget_auth_token.present? json.widget_auth_token @widget_auth_token if @widget_auth_token.present?

View File

@@ -1,5 +1,5 @@
json.id @contact.id json.id @contact.id
json.name @contact.name json.has_email @contact.email.present?
json.email @contact.email json.has_name @contact.name.present?
json.phone_number @contact.phone_number json.has_phone_number @contact.phone_number.present?
json.identifier @contact.identifier json.identifier @contact.identifier

View File

@@ -1,4 +1,4 @@
json.id @contact.id json.id @contact.id
json.name @contact.name json.has_email @contact.email.present?
json.email @contact.email json.has_name @contact.name.present?
json.phone_number @contact.phone_number json.has_phone_number @contact.phone_number.present?

View File

@@ -48,7 +48,9 @@ RSpec.describe '/api/v1/widget/contacts', type: :request do
headers: { 'X-Auth-Token' => token }, headers: { 'X-Auth-Token' => token },
as: :json as: :json
body = response.parsed_body body = response.parsed_body
expect(body['phone_number']).to eq('+745623239') expect(body['has_phone_number']).to be true
contact.reload
expect(contact.phone_number).to eq('+745623239')
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
end end
@@ -58,7 +60,9 @@ RSpec.describe '/api/v1/widget/contacts', type: :request do
headers: { 'X-Auth-Token' => token }, headers: { 'X-Auth-Token' => token },
as: :json as: :json
body = response.parsed_body body = response.parsed_body
expect(body['phone_number']).to eq('+245623239') expect(body['has_phone_number']).to be true
contact.reload
expect(contact.phone_number).to eq('+245623239')
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
end end
@@ -68,7 +72,33 @@ RSpec.describe '/api/v1/widget/contacts', type: :request do
headers: { 'X-Auth-Token' => token }, headers: { 'X-Auth-Token' => token },
as: :json as: :json
body = response.parsed_body body = response.parsed_body
expect(body['email']).to eq('test@test.com') expect(body['has_email']).to be true
contact.reload
expect(contact.email).to eq('test@test.com')
expect(response).to have_http_status(:success)
end
it 'dont update email if empty value email passed' do
patch '/api/v1/widget/contact',
params: params.merge({ email: '' }),
headers: { 'X-Auth-Token' => token },
as: :json
body = response.parsed_body
expect(body['has_email']).to be true
contact.reload
expect(contact.email).to eq('test@test.com')
expect(response).to have_http_status(:success)
end
it 'dont update email if nil value email passed' do
patch '/api/v1/widget/contact',
params: params.merge({ email: nil }),
headers: { 'X-Auth-Token' => token },
as: :json
body = response.parsed_body
expect(body['has_email']).to be true
contact.reload
expect(contact.email).to eq('test@test.com')
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
end end
@@ -78,7 +108,9 @@ RSpec.describe '/api/v1/widget/contacts', type: :request do
headers: { 'X-Auth-Token' => token }, headers: { 'X-Auth-Token' => token },
as: :json as: :json
body = response.parsed_body body = response.parsed_body
expect(body['email']).to eq('test-1@test.com') expect(body['has_email']).to be true
contact.reload
expect(contact.email).to eq('test-1@test.com')
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
end end
end end

View File

@@ -190,17 +190,19 @@ RSpec.describe '/api/v1/widget/conversations/toggle_typing', type: :request do
describe 'POST /api/v1/widget/conversations/transcript' do describe 'POST /api/v1/widget/conversations/transcript' do
context 'with a conversation' do context 'with a conversation' do
it 'sends transcript email' do it 'sends transcript email' do
contact.update(email: 'test@test.com')
mailer = double mailer = double
allow(ConversationReplyMailer).to receive(:with).and_return(mailer) allow(ConversationReplyMailer).to receive(:with).and_return(mailer)
allow(mailer).to receive(:conversation_transcript) allow(mailer).to receive(:conversation_transcript)
post '/api/v1/widget/conversations/transcript', post '/api/v1/widget/conversations/transcript',
headers: { 'X-Auth-Token' => token }, headers: { 'X-Auth-Token' => token },
params: { website_token: web_widget.website_token, email: 'test@test.com' }, params: { website_token: web_widget.website_token },
as: :json as: :json
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(mailer).to have_received(:conversation_transcript).with(conversation, 'test@test.com') expect(mailer).to have_received(:conversation_transcript).with(conversation, 'test@test.com')
contact.update(email: nil)
end end
end end
end end