search_controller.rb 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. # Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  2. class SearchController < ApplicationController
  3. prepend_before_action :authentication_check
  4. # GET|POST /api/v1/search
  5. # GET|POST /api/v1/search/:objects
  6. def search_generic
  7. # get params
  8. query = params[:query]
  9. if query.respond_to?(:permit!)
  10. query = query.permit!.to_h
  11. end
  12. limit = params[:limit] || 10
  13. # convert objects string into array of class names
  14. # e.g. user-ticket-another_object = %w( User Ticket AnotherObject )
  15. objects = if params[:objects]
  16. params[:objects].split('-').map(&:camelize)
  17. else
  18. Setting.get('models_searchable')
  19. end
  20. # get priorities of result
  21. objects_in_order = []
  22. objects_in_order_hash = {}
  23. objects.each do |object|
  24. local_class = object.constantize
  25. preferences = local_class.search_preferences(current_user)
  26. next if !preferences
  27. objects_in_order_hash[preferences[:prio]] = local_class
  28. end
  29. objects_in_order_hash.keys.sort.reverse_each do |prio|
  30. objects_in_order.push objects_in_order_hash[prio]
  31. end
  32. generic_search_params = {
  33. query: query,
  34. limit: limit,
  35. current_user: current_user,
  36. ids: params[:ids],
  37. }
  38. # try search index backend
  39. assets = {}
  40. result = []
  41. if SearchIndexBackend.enabled?
  42. # get direct search index based objects
  43. objects_with_direct_search_index = []
  44. objects_without_direct_search_index = []
  45. objects.each do |object|
  46. preferences = object.constantize.search_preferences(current_user)
  47. next if !preferences
  48. if preferences[:direct_search_index]
  49. objects_with_direct_search_index.push object
  50. else
  51. objects_without_direct_search_index.push object
  52. end
  53. end
  54. # do only one query to index search backend
  55. if objects_with_direct_search_index.present?
  56. items = SearchIndexBackend.search(query, objects_with_direct_search_index, limit: limit, ids: params[:ids])
  57. items.each do |item|
  58. local_class = item[:type].constantize
  59. record = local_class.lookup(id: item[:id])
  60. next if !record
  61. assets = record.assets(assets)
  62. item[:type] = local_class.to_app_model.to_s
  63. result.push item
  64. end
  65. end
  66. # e. g. do ticket query by Ticket class to handle ticket permissions
  67. objects_without_direct_search_index.each do |object|
  68. object_result = search_generic_backend(object.constantize, assets, generic_search_params)
  69. if object_result.present?
  70. result.concat(object_result)
  71. end
  72. end
  73. # sort order by object priority
  74. result_in_order = []
  75. objects_in_order.each do |object|
  76. result.each do |item|
  77. next if item[:type] != object.to_app_model.to_s
  78. item[:id] = item[:id].to_i
  79. result_in_order.push item
  80. end
  81. end
  82. result = result_in_order
  83. else
  84. # do query
  85. objects_in_order.each do |object|
  86. object_result = search_generic_backend(object, assets, generic_search_params)
  87. if object_result.present?
  88. result.concat(object_result)
  89. end
  90. end
  91. end
  92. render json: {
  93. assets: assets,
  94. result: result,
  95. }
  96. end
  97. private
  98. =begin
  99. search generic backend
  100. SearchController#search_generic_backend(
  101. Ticket, # object
  102. {}, # assets
  103. query: "search query",
  104. limit: 10,
  105. current_user: user,
  106. )
  107. =end
  108. def search_generic_backend(object, assets, params)
  109. found_objects = object.search(params)
  110. result = []
  111. found_objects.each do |found_object|
  112. item = {
  113. id: found_object.id,
  114. type: found_object.class.to_app_model.to_s
  115. }
  116. result.push item
  117. assets = found_object.assets(assets)
  118. end
  119. result
  120. end
  121. end