search_controller.rb 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. # Copyright (C) 2012-2016 Zammad Foundation, http://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. # enable search only for users with valid session
  8. if !current_user
  9. response_access_deny
  10. return true
  11. end
  12. # get params
  13. query = params[:query]
  14. if query.respond_to?(:permit!)
  15. query = query.permit!.to_h
  16. end
  17. limit = params[:limit] || 10
  18. # convert objects string into array of class names
  19. # e.g. user-ticket-another_object = %w( User Ticket AnotherObject )
  20. objects = if !params[:objects]
  21. Setting.get('models_searchable')
  22. else
  23. params[:objects].split('-').map(&:camelize)
  24. end
  25. # get priorities of result
  26. objects_in_order = []
  27. objects_in_order_hash = {}
  28. objects.each do |object|
  29. local_class = object.constantize
  30. preferences = local_class.search_preferences(current_user)
  31. next if !preferences
  32. objects_in_order_hash[preferences[:prio]] = local_class
  33. end
  34. objects_in_order_hash.keys.sort.reverse_each do |prio|
  35. objects_in_order.push objects_in_order_hash[prio]
  36. end
  37. # try search index backend
  38. assets = {}
  39. result = []
  40. if SearchIndexBackend.enabled?
  41. # get direct search index based objects
  42. objects_with_direct_search_index = []
  43. objects_without_direct_search_index = []
  44. objects.each do |object|
  45. preferences = object.constantize.search_preferences(current_user)
  46. next if !preferences
  47. if preferences[:direct_search_index]
  48. objects_with_direct_search_index.push object
  49. else
  50. objects_without_direct_search_index.push object
  51. end
  52. end
  53. # do only one query to index search backend
  54. if objects_with_direct_search_index.present?
  55. items = SearchIndexBackend.search(query, limit, objects_with_direct_search_index)
  56. items.each do |item|
  57. require_dependency item[:type].to_filename
  58. local_class = Kernel.const_get(item[:type])
  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, query, limit, current_user, assets)
  69. if object_result.present?
  70. result = 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, query, limit, current_user, assets)
  87. if object_result.present?
  88. result = 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. def search_generic_backend(object, query, limit, current_user, assets)
  99. found_objects = object.search(
  100. query: query,
  101. limit: limit,
  102. current_user: current_user,
  103. )
  104. result = []
  105. found_objects.each do |found_object|
  106. item = {
  107. id: found_object.id,
  108. type: found_object.class.to_app_model.to_s
  109. }
  110. result.push item
  111. assets = found_object.assets(assets)
  112. end
  113. result
  114. end
  115. end