signature_detection.rb 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. module SignatureDetection
  2. =begin
  3. try to detect the signature in list of articles for example
  4. signature = SignatureDetection.find_signature(string_list)
  5. returns
  6. signature = '...signature possible match...'
  7. =end
  8. def self.find_signature(string_list)
  9. # hash with possible signature and count of matches in string list
  10. possible_signatures = {}
  11. # loop all strings in array
  12. ( 0..string_list.length - 1 ).each {|main_string_index|
  13. break if main_string_index + 1 > string_list.length - 1
  14. # loop all all strings in array except of the previous index
  15. ( main_string_index + 1..string_list.length - 1 ).each {|second_string_index|
  16. # get content of string 1
  17. string1_content = string_list[main_string_index]
  18. # get content of string 2
  19. string2_content = string_list[second_string_index]
  20. # diff strings
  21. diff_result = Diffy::Diff.new(string1_content, string2_content)
  22. # split diff result by new line
  23. diff_result_array = diff_result.to_s.split("\n")
  24. # define start index for blocks with no difference
  25. match_block = nil
  26. # loop of lines of the diff result
  27. ( 0..diff_result_array.length - 1 ).each {|diff_string_index|
  28. # if no block with difference is defined then we try to find a string block without a difference
  29. if !match_block
  30. match_block = diff_string_index
  31. end
  32. # get line of diff result with current loop inde
  33. line = diff_result_array[diff_string_index]
  34. # check if the line starts with
  35. # + = new content incoming
  36. # - = removed content
  37. # \ = end of file
  38. # or if the current line is the last line of the diff result
  39. next if line !~ /^(\\|\+|\-)/i && diff_string_index != diff_result_array.length - 1
  40. # if the count of the lines without any difference is higher than 5 lines
  41. if diff_string_index - match_block > 5
  42. # define the block size without any difference
  43. # except "-" because in this case 1 line is removed to much
  44. match_block_total = diff_string_index + (line =~ /^(\\|\+)/i ? -1 : 0)
  45. # get string of possible signature
  46. match_content = ''
  47. ( match_block..match_block_total ).each {|match_block_index|
  48. match_content += "#{diff_result_array[match_block_index][1..-1]}\n"
  49. }
  50. # count the match of the signature in string list to rank
  51. # the signature
  52. possible_signatures[match_content] ||= 0
  53. possible_signatures[match_content] += 1
  54. break
  55. end
  56. match_block = nil
  57. }
  58. }
  59. }
  60. # loop all possible signature by rating and return highest rating
  61. possible_signatures.sort { |a1, a2| a2[1].to_i <=> a1[1].to_i }.map do |content, _score|
  62. return content.chomp
  63. end
  64. nil
  65. end
  66. =begin
  67. this function will search for a signature string in a string (e.g. article) and return the line number of the signature start
  68. signature_line = SignatureDetection.find_signature_line(signature, string)
  69. returns
  70. signature_line = 123
  71. or
  72. signature_line = nil
  73. =end
  74. def self.find_signature_line(signature, string)
  75. # try to find the char position of the signature
  76. search_position = string.index(signature)
  77. return if search_position.nil?
  78. # count new lines up to signature
  79. string[0..search_position].split("\n").length + 1
  80. end
  81. =begin
  82. this function will search for a signature string in all articles of a given user_id
  83. signature = SignatureDetection.by_user_id(user_id)
  84. returns
  85. signature = '...signature possible match...'
  86. =end
  87. def self.by_user_id(user_id)
  88. type = Ticket::Article::Type.lookup(name: 'email')
  89. sender = Ticket::Article::Sender.lookup(name: 'Customer')
  90. article_bodies = []
  91. tickets = Ticket.where(created_by_id: user_id, create_article_type_id: type.id, create_article_sender_id: sender.id).limit(5).order(id: :desc)
  92. tickets.each {|ticket|
  93. article = ticket.articles.first
  94. next if !article
  95. article_bodies.push article.body
  96. }
  97. find_signature( article_bodies )
  98. end
  99. =begin
  100. rebuild signature for each user
  101. SignatureDetection.rebuild_all_user
  102. returns
  103. true/false
  104. =end
  105. def self.rebuild_all_user
  106. User.select('id').where(active: true).order(id: :desc).each {|local_user|
  107. rebuild_user(local_user.id)
  108. }
  109. true
  110. end
  111. =begin
  112. rebuild signature for user
  113. SignatureDetection.rebuild_user(user_id)
  114. returns
  115. true/false
  116. =end
  117. def self.rebuild_user(user_id)
  118. signature_detection = by_user_id(user_id)
  119. return if !signature_detection
  120. user = User.find(user_id)
  121. return if user.preferences[:signature_detection] == signature_detection
  122. user.preferences[:signature_detection] = signature_detection
  123. user.save
  124. true
  125. end
  126. =begin
  127. rebuild signature for all articles
  128. SignatureDetection.rebuild_all_articles
  129. returns
  130. true/false
  131. =end
  132. def self.rebuild_all_articles
  133. article_type = Ticket::Article::Type.lookup(name: 'email')
  134. Ticket::Article.select('id').where(type_id: article_type.id).order(id: :desc).each {|local_article|
  135. article = Ticket::Article.find(local_article.id)
  136. user = User.find(article.created_by_id)
  137. next if !user.preferences[:signature_detection]
  138. signature_line = find_signature_line(user.preferences[:signature_detection], article.body)
  139. next if !signature_line
  140. next if article.preferences[:signature_detection] == signature_line
  141. article.preferences[:signature_detection] = signature_line
  142. article.save
  143. }
  144. true
  145. end
  146. end