fix: CC conditions when the last email is from someone else (#7010)

This commit is contained in:
Shivam Mishra
2023-06-29 08:58:44 +05:30
committed by GitHub
parent 40830046e8
commit 28e7a5d228
7 changed files with 116 additions and 18 deletions

View File

@@ -48,17 +48,22 @@ class Messages::MessageBuilder
def process_emails def process_emails
return unless @conversation.inbox&.inbox_type == 'Email' return unless @conversation.inbox&.inbox_type == 'Email'
cc_emails = [] cc_emails = process_email_string(@params[:cc_emails])
cc_emails = @params[:cc_emails].gsub(/\s+/, '').split(',') if @params[:cc_emails].present? bcc_emails = process_email_string(@params[:bcc_emails])
to_emails = process_email_string(@params[:to_emails])
bcc_emails = [] all_email_addresses = cc_emails + bcc_emails + to_emails
bcc_emails = @params[:bcc_emails].gsub(/\s+/, '').split(',') if @params[:bcc_emails].present?
all_email_addresses = cc_emails + bcc_emails
validate_email_addresses(all_email_addresses) validate_email_addresses(all_email_addresses)
@message.content_attributes[:cc_emails] = cc_emails @message.content_attributes[:cc_emails] = cc_emails
@message.content_attributes[:bcc_emails] = bcc_emails @message.content_attributes[:bcc_emails] = bcc_emails
@message.content_attributes[:to_emails] = to_emails
end
def process_email_string(email_string)
return [] if email_string.blank?
email_string.gsub(/\s+/, '').split(',')
end end
def validate_email_addresses(all_emails) def validate_email_addresses(all_emails)

View File

@@ -10,6 +10,7 @@ export const buildCreatePayload = ({
files, files,
ccEmails = '', ccEmails = '',
bccEmails = '', bccEmails = '',
toEmails = '',
templateParams, templateParams,
}) => { }) => {
let payload; let payload;
@@ -25,6 +26,9 @@ export const buildCreatePayload = ({
payload.append('echo_id', echoId); payload.append('echo_id', echoId);
payload.append('cc_emails', ccEmails); payload.append('cc_emails', ccEmails);
payload.append('bcc_emails', bccEmails); payload.append('bcc_emails', bccEmails);
if (toEmails) {
payload.append('to_emails', toEmails);
}
} else { } else {
payload = { payload = {
content: message, content: message,
@@ -33,6 +37,7 @@ export const buildCreatePayload = ({
content_attributes: contentAttributes, content_attributes: contentAttributes,
cc_emails: ccEmails, cc_emails: ccEmails,
bcc_emails: bccEmails, bcc_emails: bccEmails,
to_emails: toEmails,
template_params: templateParams, template_params: templateParams,
}; };
} }
@@ -53,6 +58,7 @@ class MessageApi extends ApiClient {
files, files,
ccEmails = '', ccEmails = '',
bccEmails = '', bccEmails = '',
toEmails = '',
templateParams, templateParams,
}) { }) {
return axios({ return axios({
@@ -66,6 +72,7 @@ class MessageApi extends ApiClient {
files, files,
ccEmails, ccEmails,
bccEmails, bccEmails,
toEmails,
templateParams, templateParams,
}), }),
}); });

View File

@@ -35,6 +35,7 @@
v-if="showReplyHead" v-if="showReplyHead"
:cc-emails.sync="ccEmails" :cc-emails.sync="ccEmails"
:bcc-emails.sync="bccEmails" :bcc-emails.sync="bccEmails"
:to-emails.sync="toEmails"
/> />
<woot-audio-recorder <woot-audio-recorder
v-if="showAudioRecorderEditor" v-if="showAudioRecorderEditor"
@@ -238,6 +239,7 @@ export default {
hasSlashCommand: false, hasSlashCommand: false,
bccEmails: '', bccEmails: '',
ccEmails: '', ccEmails: '',
toEmails: '',
doAutoSaveDraft: () => {}, doAutoSaveDraft: () => {},
showWhatsAppTemplatesModal: false, showWhatsAppTemplatesModal: false,
updateEditorSelectionWith: '', updateEditorSelectionWith: '',
@@ -528,7 +530,7 @@ export default {
this.replyType = REPLY_EDITOR_MODES.NOTE; this.replyType = REPLY_EDITOR_MODES.NOTE;
} }
this.setCCEmailFromLastChat(); this.setCCAndToEmailsFromLastChat();
}, },
conversationIdByRoute(conversationId, oldConversationId) { conversationIdByRoute(conversationId, oldConversationId) {
if (conversationId !== oldConversationId) { if (conversationId !== oldConversationId) {
@@ -562,7 +564,7 @@ export default {
// working even if input/textarea is focussed. // working even if input/textarea is focussed.
document.addEventListener('paste', this.onPaste); document.addEventListener('paste', this.onPaste);
document.addEventListener('keydown', this.handleKeyEvents); document.addEventListener('keydown', this.handleKeyEvents);
this.setCCEmailFromLastChat(); this.setCCAndToEmailsFromLastChat();
this.doAutoSaveDraft = debounce( this.doAutoSaveDraft = debounce(
() => { () => {
this.saveDraft(this.conversationIdByRoute, this.replyType); this.saveDraft(this.conversationIdByRoute, this.replyType);
@@ -844,6 +846,7 @@ export default {
clearEmailField() { clearEmailField() {
this.ccEmails = ''; this.ccEmails = '';
this.bccEmails = ''; this.bccEmails = '';
this.toEmails = '';
}, },
toggleEmojiPicker() { toggleEmojiPicker() {
this.showEmojiPicker = !this.showEmojiPicker; this.showEmojiPicker = !this.showEmojiPicker;
@@ -1054,22 +1057,56 @@ export default {
messagePayload.bccEmails = this.bccEmails; messagePayload.bccEmails = this.bccEmails;
} }
if (this.toEmails && !this.isOnPrivateNote) {
messagePayload.toEmails = this.toEmails;
}
return messagePayload; return messagePayload;
}, },
setCcEmails(value) { setCcEmails(value) {
this.bccEmails = value.bccEmails; this.bccEmails = value.bccEmails;
this.ccEmails = value.ccEmails; this.ccEmails = value.ccEmails;
}, },
setCCEmailFromLastChat() { setCCAndToEmailsFromLastChat() {
if (this.lastEmail) { if (!this.lastEmail) return;
const {
content_attributes: { email: emailAttributes = {} }, const {
} = this.lastEmail; content_attributes: { email: emailAttributes = {} },
const cc = emailAttributes.cc || []; } = this.lastEmail;
const bcc = emailAttributes.bcc || [];
this.ccEmails = cc.join(', '); // Retrieve the email of the current conversation's sender
this.bccEmails = bcc.join(', '); const conversationContact = this.currentChat?.meta?.sender?.email || '';
let cc = [...emailAttributes.cc] || [];
let to = [];
// there might be a situation where the current conversation will include a message from a third person,
// and the current conversation contact is in CC.
// This is an edge-case, reported here: CW-1511 [ONLY FOR INTERNAL REFERENCE]
// So we remove the current conversation contact's email from the CC list if present
if (cc.includes(conversationContact)) {
cc = cc.filter(email => email !== conversationContact);
} }
// If the last incoming message sender is different from the conversation contact, add them to the "to"
// and add the conversation contact to the CC
if (!emailAttributes.from.includes(conversationContact)) {
to.push(...emailAttributes.from);
cc.push(conversationContact);
}
// Remove the conversation contact's email from the BCC list if present
let bcc = (emailAttributes.bcc || []).filter(
email => email !== conversationContact
);
// Ensure only unique email addresses are in the CC list
bcc = [...new Set(bcc)];
cc = [...new Set(cc)];
to = [...new Set(to)];
this.ccEmails = cc.join(', ');
this.bccEmails = bcc.join(', ');
this.toEmails = to.join(', ');
}, },
}, },
}; };

View File

@@ -1,5 +1,21 @@
<template> <template>
<div> <div>
<div v-if="toEmails">
<div class="input-group small" :class="{ error: $v.toEmailsVal.$error }">
<label class="input-group-label">
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.TO') }}
</label>
<div class="input-group-field">
<woot-input
v-model.trim="$v.toEmailsVal.$model"
type="text"
:class="{ error: $v.toEmailsVal.$error }"
:placeholder="$t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.PLACEHOLDER')"
@blur="onBlur"
/>
</div>
</div>
</div>
<div class="input-group-wrap"> <div class="input-group-wrap">
<div class="input-group small" :class="{ error: $v.ccEmailsVal.$error }"> <div class="input-group small" :class="{ error: $v.ccEmailsVal.$error }">
<label class="input-group-label"> <label class="input-group-label">
@@ -53,6 +69,7 @@
<script> <script>
import { validEmailsByComma } from './helpers/emailHeadHelper'; import { validEmailsByComma } from './helpers/emailHeadHelper';
export default { export default {
props: { props: {
ccEmails: { ccEmails: {
@@ -63,12 +80,17 @@ export default {
type: String, type: String,
default: '', default: '',
}, },
toEmails: {
type: String,
default: '',
},
}, },
data() { data() {
return { return {
showBcc: false, showBcc: false,
ccEmailsVal: '', ccEmailsVal: '',
bccEmailsVal: '', bccEmailsVal: '',
toEmailsVal: '',
}; };
}, },
watch: { watch: {
@@ -82,10 +104,16 @@ export default {
this.ccEmailsVal = newVal; this.ccEmailsVal = newVal;
} }
}, },
toEmails(newVal) {
if (newVal !== this.toEmailsVal) {
this.toEmailsVal = newVal;
}
},
}, },
mounted() { mounted() {
this.ccEmailsVal = this.ccEmails; this.ccEmailsVal = this.ccEmails;
this.bccEmailsVal = this.bccEmails; this.bccEmailsVal = this.bccEmails;
this.toEmailsVal = this.toEmails;
}, },
validations: { validations: {
ccEmailsVal: { ccEmailsVal: {
@@ -98,6 +126,11 @@ export default {
return validEmailsByComma(value); return validEmailsByComma(value);
}, },
}, },
toEmailsVal: {
hasValidEmails(value) {
return validEmailsByComma(value);
},
},
}, },
methods: { methods: {
handleAddBcc() { handleAddBcc() {
@@ -107,6 +140,7 @@ export default {
this.$v.$touch(); this.$v.$touch();
this.$emit('update:bccEmails', this.bccEmailsVal); this.$emit('update:bccEmails', this.bccEmailsVal);
this.$emit('update:ccEmails', this.ccEmailsVal); this.$emit('update:ccEmails', this.ccEmailsVal);
this.$emit('update:toEmails', this.toEmailsVal);
}, },
}, },
}; };

View File

@@ -147,6 +147,7 @@
"STOP_AUDIO_RECORDING": "Stop audio recording", "STOP_AUDIO_RECORDING": "Stop audio recording",
"": "", "": "",
"EMAIL_HEAD": { "EMAIL_HEAD": {
"TO": "TO",
"ADD_BCC": "Add bcc", "ADD_BCC": "Add bcc",
"CC": { "CC": {
"LABEL": "CC", "LABEL": "CC",

View File

@@ -162,6 +162,20 @@ class ConversationReplyMailer < ApplicationMailer
[content_attributes[:cc_emails], content_attributes[:bcc_emails]] [content_attributes[:cc_emails], content_attributes[:bcc_emails]]
end end
def to_emails_from_content_attributes
content_attributes = @conversation.messages.outgoing.last&.content_attributes
return [] unless content_attributes
return [] unless content_attributes[:to_emails]
content_attributes[:to_emails]
end
def to_emails
# if there is no to_emails from content_attributes, send it to @contact&.email
to_emails_from_content_attributes.presence || [@contact&.email]
end
def inbound_email_enabled? def inbound_email_enabled?
@inbound_email_enabled ||= @account.feature_enabled?('inbound_emails') && @account.inbound_email_domain @inbound_email_enabled ||= @account.feature_enabled?('inbound_emails') && @account.inbound_email_domain
.present? && @account.support_email.present? .present? && @account.support_email.present?

View File

@@ -1,7 +1,7 @@
module ConversationReplyMailerHelper module ConversationReplyMailerHelper
def prepare_mail(cc_bcc_enabled) def prepare_mail(cc_bcc_enabled)
@options = { @options = {
to: @contact&.email, to: to_emails,
from: email_from, from: email_from,
reply_to: email_reply_to, reply_to: email_reply_to,
subject: mail_subject, subject: mail_subject,