Browse Source

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

Mantas 4 years ago
parent
commit
1f76712933

+ 4 - 3
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 = "<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.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>"
 
@@ -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) + '<br><br>'
 
+
 App.Config.set('200-EmailReply', EmailReply, 'TicketZoomArticleAction')

+ 79 - 0
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]

+ 82 - 7
spec/system/ticket/update/full_quote_header_spec.rb

@@ -23,7 +23,7 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
         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 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
         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 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
         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 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
         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 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
 
   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 @@ RSpec.describe 'Ticket > Update > Full Quote Header', type: :system, time_zone:
       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