search.rb 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
  2. module Ticket::Search
  3. extend ActiveSupport::Concern
  4. included do
  5. include HasSearchSortable
  6. end
  7. # methods defined here are going to extend the class, not the instance of it
  8. class_methods do
  9. =begin
  10. search tickets preferences
  11. result = Ticket.search_preferences(user_model)
  12. returns if user has permissions to search
  13. result = {
  14. prio: 3000,
  15. direct_search_index: false
  16. }
  17. returns if user has no permissions to search
  18. result = false
  19. =end
  20. def search_preferences(_current_user)
  21. {
  22. prio: 3000,
  23. direct_search_index: false,
  24. }
  25. end
  26. =begin
  27. search tickets via search index
  28. result = Ticket.search(
  29. current_user: User.find(123),
  30. query: 'search something',
  31. limit: 15,
  32. offset: 100,
  33. )
  34. returns
  35. result = [ticket_model1, ticket_model2]
  36. search tickets via search index
  37. result = Ticket.search(
  38. current_user: User.find(123),
  39. query: 'search something',
  40. limit: 15,
  41. offset: 100,
  42. full: false,
  43. )
  44. returns
  45. result = [1,3,5,6,7]
  46. search tickets via database
  47. result = Ticket.search(
  48. current_user: User.find(123),
  49. query: 'some query', # query or condition is required
  50. condition: {
  51. 'tickets.owner_id' => {
  52. operator: 'is',
  53. value: user.id,
  54. },
  55. 'tickets.state_id' => {
  56. operator: 'is',
  57. value: Ticket::State.where(
  58. state_type_id: Ticket::StateType.where(
  59. name: [
  60. 'pending reminder',
  61. 'pending action',
  62. ],
  63. ).map(&:id),
  64. },
  65. ),
  66. },
  67. limit: 15,
  68. offset: 100,
  69. # sort single column
  70. sort_by: 'created_at',
  71. order_by: 'asc',
  72. # sort multiple columns
  73. sort_by: [ 'created_at', 'updated_at' ],
  74. order_by: [ 'asc', 'desc' ],
  75. full: false,
  76. )
  77. returns
  78. result = [1,3,5,6,7]
  79. =end
  80. def search(params)
  81. # get params
  82. query = params[:query]
  83. condition = params[:condition]
  84. limit = params[:limit] || 12
  85. offset = params[:offset] || 0
  86. current_user = params[:current_user]
  87. full = false
  88. if params[:full] == true || params[:full] == 'true' || !params.key?(:full)
  89. full = true
  90. end
  91. # check sort
  92. sort_by = search_get_sort_by(params, 'updated_at')
  93. # check order
  94. order_by = search_get_order_by(params, 'desc')
  95. # try search index backend
  96. if condition.blank? && SearchIndexBackend.enabled?
  97. query_extension = {}
  98. query_extension['bool'] = {}
  99. query_extension['bool']['must'] = []
  100. if current_user.permissions?('ticket.agent')
  101. group_ids = current_user.group_ids_access('read')
  102. access_condition = {
  103. 'query_string' => { 'default_field' => 'group_id', 'query' => "\"#{group_ids.join('" OR "')}\"" }
  104. }
  105. else
  106. access_condition = if !current_user.organization || ( !current_user.organization.shared || current_user.organization.shared == false )
  107. {
  108. 'query_string' => { 'default_field' => 'customer_id', 'query' => current_user.id }
  109. }
  110. # customer_id: XXX
  111. # conditions = [ 'customer_id = ?', current_user.id ]
  112. else
  113. {
  114. 'query_string' => { 'query' => "customer_id:#{current_user.id} OR organization_id:#{current_user.organization.id}" }
  115. }
  116. # customer_id: XXX OR organization_id: XXX
  117. # conditions = [ '( customer_id = ? OR organization_id = ? )', current_user.id, current_user.organization.id ]
  118. end
  119. end
  120. query_extension['bool']['must'].push access_condition
  121. items = SearchIndexBackend.search(query, 'Ticket', limit: limit,
  122. query_extension: query_extension,
  123. from: offset,
  124. sort_by: sort_by,
  125. order_by: order_by)
  126. if !full
  127. ids = []
  128. items.each do |item|
  129. ids.push item[:id]
  130. end
  131. return ids
  132. end
  133. tickets = []
  134. items.each do |item|
  135. ticket = Ticket.lookup(id: item[:id])
  136. next if !ticket
  137. tickets.push ticket
  138. end
  139. return tickets
  140. end
  141. # fallback do sql query
  142. access_condition = Ticket.access_condition(current_user, 'read')
  143. # do query
  144. # - stip out * we already search for *query* -
  145. order_select_sql = search_get_order_select_sql(sort_by, order_by, 'tickets.updated_at')
  146. order_sql = search_get_order_sql(sort_by, order_by, 'tickets.updated_at DESC')
  147. if query
  148. query.delete! '*'
  149. tickets_all = Ticket.select("DISTINCT(tickets.id), #{order_select_sql}")
  150. .where(access_condition)
  151. .where('(tickets.title LIKE ? OR tickets.number LIKE ? OR ticket_articles.body LIKE ? OR ticket_articles.from LIKE ? OR ticket_articles.to LIKE ? OR ticket_articles.subject LIKE ?)', "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%" )
  152. .joins(:articles)
  153. .order(order_sql)
  154. .offset(offset)
  155. .limit(limit)
  156. else
  157. query_condition, bind_condition, tables = selector2sql(condition)
  158. tickets_all = Ticket.select("DISTINCT(tickets.id), #{order_select_sql}")
  159. .joins(tables)
  160. .where(access_condition)
  161. .where(query_condition, *bind_condition)
  162. .order(order_sql)
  163. .offset(offset)
  164. .limit(limit)
  165. end
  166. # build result list
  167. if !full
  168. ids = []
  169. tickets_all.each do |ticket|
  170. ids.push ticket.id
  171. end
  172. return ids
  173. end
  174. tickets = []
  175. tickets_all.each do |ticket|
  176. tickets.push Ticket.lookup(id: ticket.id)
  177. end
  178. tickets
  179. end
  180. end
  181. end