signature_detection_spec.rb 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. require 'rails_helper'
  2. RSpec.describe SignatureDetection do
  3. describe '.find_signature' do
  4. context 'when given an array of hashes' do
  5. let(:messages) do
  6. raw_message_files.map do |f|
  7. { content: File.read(f), content_type: content_type }
  8. end
  9. end
  10. context 'with plain text messages in their :content keys (sample input 1)' do
  11. let(:content_type) { 'text/plain' }
  12. let(:raw_message_files) do
  13. [
  14. Rails.root.join('test/data/email_signature_detection/client_a_1.txt'),
  15. Rails.root.join('test/data/email_signature_detection/client_a_2.txt'),
  16. Rails.root.join('test/data/email_signature_detection/client_a_3.txt')
  17. ]
  18. end
  19. it 'returns the first 5–10-line substring they share in common' do
  20. expect(described_class.find_signature(messages)).to eq(<<~SIG.chomp)
  21. Mit freundlichen Grüßen
  22. Bob Smith
  23. Berechtigungen und dez. Department
  24. ________________________________
  25. Musik AG
  26. Berechtigungen und dez. Department (ITPBM)
  27. Kastanien 2
  28. SIG
  29. end
  30. end
  31. context 'with plain text messages in their :content keys (sample input 2)' do
  32. let(:content_type) { 'text/plain' }
  33. let(:raw_message_files) do
  34. [
  35. Rails.root.join('test/data/email_signature_detection/client_b_1.txt'),
  36. Rails.root.join('test/data/email_signature_detection/client_b_2.txt'),
  37. Rails.root.join('test/data/email_signature_detection/client_b_3.txt')
  38. ]
  39. end
  40. it 'returns the first 5–10-line substring they share in common' do
  41. expect(described_class.find_signature(messages)).to eq(<<~SIG.chomp)
  42. Freundliche Grüße
  43. Günter Lässig
  44. Lokale Daten
  45. Music GmbH
  46. Baustraße 123, 12345 Max City
  47. Telefon 0123 5432114
  48. Telefax 0123 5432139
  49. SIG
  50. end
  51. end
  52. context 'with HTML messages in their :content keys' do
  53. let(:content_type) { 'text/html' }
  54. let(:raw_message_files) do
  55. [
  56. Rails.root.join('test/data/email_signature_detection/client_c_1.html'),
  57. Rails.root.join('test/data/email_signature_detection/client_c_2.html'),
  58. Rails.root.join('test/data/email_signature_detection/client_c_3.html')
  59. ]
  60. end
  61. it 'converts messages (via #html2text) then returns the first 5–10-line substring they share in common' do
  62. expect(described_class.find_signature(messages)).to eq(<<~SIG.chomp)
  63. ChristianSmith
  64. Technik
  65. Tel: +49 12 34 56 78 441
  66. Fax: +49 12 34 56 78 499
  67. Email: Christian.Smith@example.com
  68. Web: www.example.com
  69. ABC KFZ- und Flugzeug B.V. & Co. KG
  70. Hauptverwaltung
  71. SIG
  72. end
  73. end
  74. end
  75. context 'when input messages do not share 5-line common substrings' do
  76. let(:messages) do
  77. Array.new(2) { { content: <<~RAW, content_type: 'text/plain' } }
  78. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  79. Ut ut tincidunt nunc. Sed mattis aliquam tellus sit amet lacinia.
  80. Mauris fermentum dictum aliquet.
  81. Nam ex risus, gravida et ornare ut, mollis non sapien.
  82. RAW
  83. end
  84. it 'doesn’t break' do
  85. expect { described_class.find_signature(messages) }.not_to raise_error
  86. end
  87. end
  88. context 'when message contains exchange warning (#3571)' do
  89. let(:content_type) { 'text/html' }
  90. let(:messages) do
  91. [
  92. { content: '<div><span style="color:#9c6500;">CAUTION:</span> This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.</div><br><div><p>actual content</p><div><p>actual content 2</p></div><p>&nbsp;</p><div><p>actual quote</p></div><div><blockquote><p>actual quote</p></blockquote></div><div><p>&nbsp;</p></div><p>&nbsp;</p></div></div>', content_type: 'text/html' },
  93. { content: '<div><span style="color:#9c6500;">CAUTION:</span> This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.</div><br><div><p>333 content</p><div><p>4452134123 content 2</p></div><p>&nbsp;</p><div><p>123124123 quote</p></div><div><blockquote><p>123141 144234</p></blockquote></div><div><p>&nbsp;</p></div><p>&nbsp;</p></div></div>', content_type: 'text/html' },
  94. { content: '<div><span style="color:#9c6500;">CAUTION:</span> This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.</div><br><div><p>333 content</p><div><p>4452134123 content 2</p></div><p>&nbsp;</p><div><p>9999 quote</p></div><div><blockquote><p>999 144234</p></blockquote></div><div><p>&nbsp;</p></div><p>&nbsp;</p></div></div>', content_type: 'text/html' },
  95. ]
  96. end
  97. it 'does not detect the warning information as signature' do
  98. expect(described_class.find_signature(messages)).to eq(nil)
  99. end
  100. end
  101. end
  102. describe '.find_signature_line' do
  103. context 'when given a plain text message' do
  104. let(:content_type) { 'text/plain' }
  105. let(:content) { File.read(Rails.root.join('test/data/email_signature_detection/client_a_1.txt')) }
  106. context 'and a substring it contains' do
  107. let(:signature) { <<~SIG.chomp }
  108. Mit freundlichen Grüßen
  109. Bob Smith
  110. Berechtigungen und dez. Department
  111. ________________________________
  112. Musik AG
  113. Berechtigungen und dez. Department (ITPBM)
  114. Kastanien 2
  115. SIG
  116. it 'returns the line of the message where the signature begins' do
  117. expect(described_class.find_signature_line(signature, content, content_type)).to eq(10)
  118. end
  119. end
  120. end
  121. context 'when given an HTML message' do
  122. let(:content_type) { 'text/html' }
  123. let(:content) { File.read(Rails.root.join('test/data/email_signature_detection/example1.html')) }
  124. context 'and a substring it contains' do
  125. let(:signature) { <<~SIG.chomp }
  126. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  127. Bob Smith
  128. ABC Organisation
  129. EXAMPLE IT-Service GmbH
  130. Dorten 5 F&E
  131. 12345 Da / Germany
  132. Phone: +49 (0) 1234 567 890 / +49 (0) 1234 567 891
  133. Fax:     +49 (0) 1234 567 892
  134. SIG
  135. it 'converts messages (via #html2text) then returns the line of the message where the signature begins' do
  136. expect(described_class.find_signature_line(signature, content, content_type)).to eq(11)
  137. end
  138. end
  139. end
  140. end
  141. describe '.rebuild_all_articles' do
  142. context 'when a user exists with a recorded signature' do
  143. let!(:customer) { create(:customer, preferences: { signature_detection: "\nbar" }) }
  144. context 'and multiple articles exist for that customer' do
  145. let!(:articles) do
  146. [create(:ticket_article, created_by_id: customer.id, body: "foo\nfoo\nbar"),
  147. create(:ticket_article, created_by_id: customer.id, body: "foo\nbar")]
  148. end
  149. it 'updates the signature-line data of all articles' do
  150. expect { described_class.rebuild_all_articles }
  151. .to change { articles.first.reload.preferences[:signature_detection] }.to(3)
  152. .and change { articles.second.reload.preferences[:signature_detection] }.to(2)
  153. end
  154. end
  155. end
  156. end
  157. end