Fixes #3091 - Enhanced/reworked message header of forwarded mails.

This commit is contained in:
Mantas 2020-07-14 13:39:17 +03:00 committed by Thorsten Eckel
parent 41bba5dda3
commit 1f76712933
3 changed files with 165 additions and 10 deletions

View file

@ -148,7 +148,7 @@ class EmailReply extends App.Controller
selected = App.Utils.text2html(selected) selected = App.Utils.text2html(selected)
if selected if selected
quote_header = @fullQuoteHeader(article) quote_header = @replyQuoteHeader(article)
selected = "<div><br><br/></div><div><blockquote type=\'cite\'>#{quote_header}#{selected}<br></blockquote></div><div><br></div>" selected = "<div><br><br/></div><div><blockquote type=\'cite\'>#{quote_header}#{selected}<br></blockquote></div><div><br></div>"
@ -196,7 +196,7 @@ class EmailReply extends App.Controller
body = App.Utils.textCleanup(article.body) body = App.Utils.textCleanup(article.body)
body = App.Utils.text2html(body) body = App.Utils.text2html(body)
quote_header = @fullQuoteHeader(article) quote_header = App.FullQuoteHeader.fullQuoteHeaderForward(article)
body = "<br/><div>---Begin forwarded message:---<br/><br/></div><div><blockquote type=\"cite\">#{quote_header}#{body}</blockquote></div><div><br></div>" body = "<br/><div>---Begin forwarded message:---<br/><br/></div><div><blockquote type=\"cite\">#{quote_header}#{body}</blockquote></div><div><br></div>"
@ -339,7 +339,7 @@ class EmailReply extends App.Controller
true true
@fullQuoteHeader: (article) -> @replyQuoteHeader: (article) ->
if !App.Config.get('ui_ticket_zoom_article_email_full_quote_header') if !App.Config.get('ui_ticket_zoom_article_email_full_quote_header')
return '' return ''
@ -348,4 +348,5 @@ class EmailReply extends App.Controller
App.i18n.translateInline('On %s, %s wrote:', date, name) + '<br><br>' App.i18n.translateInline('On %s, %s wrote:', date, name) + '<br><br>'
App.Config.set('200-EmailReply', EmailReply, 'TicketZoomArticleAction') App.Config.set('200-EmailReply', EmailReply, 'TicketZoomArticleAction')

View file

@ -0,0 +1,79 @@
class App.FullQuoteHeader
@fullQuoteHeaderForward: (article) ->
if !App.Config.get('ui_ticket_zoom_article_email_full_quote_header')
return ''
output = document.createElement('div')
data = {
Subject: article.subject
Date: App.i18n.translateTimestamp(article.created_at)
From: @fullQuoteHeaderForwardFrom(article)
To: @fullQuoteHeaderForwardTo(article)
CC: @fullQuoteHeaderForwardCC(article)
}
for key, value of data
if value
output.append App.i18n.translateContent(key), ': ', value, document.createElement('br')
output.append document.createElement('br')
output.outerHTML
@fullQuoteHeaderForwardFrom: (article) ->
user_id = article.origin_by_id || article.created_by_id
@fullQuoteHeaderEnsurePrivacy(user_id) || @fullQuoteHeaderEnsurePrivacy(article.from) || article.from
@fullQuoteHeaderForwardTo: (article) ->
if article.type.name is 'email' || article.type.name is 'web'
@fullQuoteHeaderEnsurePrivacy(article.to) || article.to
else if article.sender.name is 'Customer' && article.type.name is 'phone'
if email_address_id = App.Group.findByAttribute('name', article.to)?.email_address_id
App.EmailAddress.find(email_address_id).displayName()
else
article.to
else if article.sender.name is 'Agent' && article.type.name is 'phone'
ticket = App.Ticket.find article.ticket_id
@fullQuoteHeaderEnsurePrivacy(ticket.customer_id) || @fullQuoteHeaderEnsurePrivacy(article.to) || article.to
else
article.to
@fullQuoteHeaderForwardCC: (article) ->
return if !article.cc
article
.cc
.split(',')
.map (elem) ->
elem.trim()
.map (elem) =>
@fullQuoteHeaderEnsurePrivacy(elem) || elem
.join(', ')
@fullQuoteHeaderEnsurePrivacyParseInput: (input) ->
switch typeof input
when 'number'
App.User.find input
when 'string'
if email = @fullQuoteHeaderExtractEmail(input)
App.User.findByAttribute('email', email)
when 'object'
input
@fullQuoteHeaderEnsurePrivacy: (input) =>
user = @fullQuoteHeaderEnsurePrivacyParseInput(input)
return if !user
output = "#{user.displayName()}"
if !user.permission('ticket.agent') && user.email
output += " <#{user.email}>"
output
@fullQuoteHeaderExtractEmail: (input) ->
if match = input.match(/<?(\S+@\S[^>]+)(>?)/)
match[1]

View file

@ -23,7 +23,7 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
click_forward click_forward
within(:richtext) do within(:richtext) do
expect(page).to contain_full_quote(ticket_article) expect(page).to contain_full_quote(ticket_article).formatted_for(:forward)
end end
end end
end end
@ -33,7 +33,21 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
highlight_and_click_reply highlight_and_click_reply
within(:richtext) do within(:richtext) do
expect(page).to contain_full_quote(ticket_article) expect(page).to contain_full_quote(ticket_article).formatted_for(:reply)
end
end
end
context 'when customer is agent' do
let(:customer) { create(:agent) }
it 'includes OP without email when forwarding' do
within(:active_content) do
click_forward
within(:richtext) do
expect(page).to contain_full_quote(ticket_article).formatted_for(:forward).ensuring_privacy(true)
end
end end
end end
end end
@ -47,7 +61,7 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
click_forward click_forward
within(:richtext) do within(:richtext) do
expect(page).not_to contain_full_quote(ticket_article) expect(page).not_to contain_full_quote(ticket_article).formatted_for(:forward)
end end
end end
end end
@ -57,7 +71,7 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
highlight_and_click_reply highlight_and_click_reply
within(:richtext) do within(:richtext) do
expect(page).not_to contain_full_quote(ticket_article) expect(page).not_to contain_full_quote(ticket_article).formatted_for(:reply)
end end
end end
end end
@ -82,11 +96,65 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
define :contain_full_quote do define :contain_full_quote do
match do match do
citation.has_text?(name) && citation.has_no_text?(email) && citation.has_text?(timestamp) confirm_content && confirm_style
end end
match_when_negated do match_when_negated do
citation.has_no_text?(name) && citation.has_no_text?(email) && citation.has_no_text?(timestamp) confirm_no_content
end
# sets expected quote format
# @param [Symbol] :forward or :reply, defaults to :reply if not set
chain :formatted_for do |style|
@style = style
end
def style
@style || :reply # rubocop:disable RSpec/InstanceVariable
end
# sets expected privacy level
# @param [Boolean] defaults to false if not set
chain :ensuring_privacy do |flag|
@ensuring_privacy = flag
end
def ensure_privacy?
@ensuring_privacy || false # rubocop:disable RSpec/InstanceVariable
end
def confirm_content
case style
when :reply
confirm_content_reply
when :forward
confirm_content_forward
end
end
def confirm_content_reply
citation.has_text?(name) && citation.has_no_text?(email) && citation.has_text?(timestamp_reply)
end
def confirm_content_forward
if ensure_privacy?
citation.has_text?(name) && citation.has_no_text?(email) && citation.has_text?(timestamp_forward)
else
citation.has_text?(name) && citation.has_text?(email) && citation.has_text?(timestamp_forward)
end
end
def confirm_no_content
citation.has_no_text?(name) && citation.has_no_text?(email) && citation.has_no_text?(timestamp_reply) && citation.has_no_text?(timestamp_forward)
end
def confirm_style
case style
when :forward
citation.text.match?(/Subject(.+)\nDate(.+)/)
when :reply
citation.text.match?(/^On(.+)wrote:$/)
end
end end
def citation def citation
@ -101,11 +169,18 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
expected.created_by.email expected.created_by.email
end end
def timestamp def timestamp_reply
expected expected
.created_at .created_at
.in_time_zone('Europe/London') .in_time_zone('Europe/London')
.strftime('%A, %B %1d, %Y, %1I:%M:%S %p') .strftime('%A, %B %1d, %Y, %1I:%M:%S %p')
end end
def timestamp_forward
expected
.created_at
.in_time_zone('Europe/London')
.strftime('%m/%d/%Y %H:%M')
end
end end
end end