diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee
index e9b19457dfe8..584ecfc70318 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee
@@ -148,7 +148,7 @@ class EmailReply extends App.Controller
selected = App.Utils.text2html(selected)
if selected
- quote_header = @fullQuoteHeader(article)
+ quote_header = @replyQuoteHeader(article)
selected = "
#{quote_header}#{selected}
"
@@ -196,7 +196,7 @@ class EmailReply extends App.Controller
body = App.Utils.textCleanup(article.body)
body = App.Utils.text2html(body)
- quote_header = @fullQuoteHeader(article)
+ quote_header = App.FullQuoteHeader.fullQuoteHeaderForward(article)
body = "
---Begin forwarded message:---
"
@@ -339,7 +339,7 @@ class EmailReply extends App.Controller
true
- @fullQuoteHeader: (article) ->
+ @replyQuoteHeader: (article) ->
if !App.Config.get('ui_ticket_zoom_article_email_full_quote_header')
return ''
@@ -348,4 +348,5 @@ class EmailReply extends App.Controller
App.i18n.translateInline('On %s, %s wrote:', date, name) + '
'
+
App.Config.set('200-EmailReply', EmailReply, 'TicketZoomArticleAction')
diff --git a/app/assets/javascripts/app/lib/app_post/full_quote_header.coffee b/app/assets/javascripts/app/lib/app_post/full_quote_header.coffee
new file mode 100644
index 000000000000..63b7a77615d2
--- /dev/null
+++ b/app/assets/javascripts/app/lib/app_post/full_quote_header.coffee
@@ -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]
diff --git a/spec/system/ticket/update/full_quote_header_spec.rb b/spec/system/ticket/update/full_quote_header_spec.rb
index 75519e83c311..4b0ae8f4a548 100644
--- a/spec/system/ticket/update/full_quote_header_spec.rb
+++ b/spec/system/ticket/update/full_quote_header_spec.rb
@@ -23,7 +23,7 @@
click_forward
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
@@ -33,7 +33,21 @@
highlight_and_click_reply
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
@@ -47,7 +61,7 @@
click_forward
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
@@ -57,7 +71,7 @@
highlight_and_click_reply
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
@@ -82,11 +96,65 @@ def highlight_and_click_reply
define :contain_full_quote do
match do
- citation.has_text?(name) && citation.has_no_text?(email) && citation.has_text?(timestamp)
+ confirm_content && confirm_style
end
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
def citation
@@ -101,11 +169,18 @@ def email
expected.created_by.email
end
- def timestamp
+ def timestamp_reply
expected
.created_at
.in_time_zone('Europe/London')
.strftime('%A, %B %1d, %Y, %1I:%M:%S %p')
end
+
+ def timestamp_forward
+ expected
+ .created_at
+ .in_time_zone('Europe/London')
+ .strftime('%m/%d/%Y %H:%M')
+ end
end
end