external_data_source.rb 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. class ExternalDataSource
  3. attr_reader :json, :parsed_items, :options
  4. def initialize(options:, term:, render_context:, limit: 10)
  5. @term = term
  6. @options = options
  7. @limit = limit
  8. @render_context = render_context
  9. end
  10. def process
  11. @json = fetch_json
  12. @parsed_items = get_items_list(@json)
  13. @parsed_items
  14. .slice(...@limit)
  15. .map do |elem|
  16. {
  17. value: get_item_value(elem),
  18. label: get_item_label(elem)
  19. }
  20. end
  21. end
  22. private
  23. def fetch_json
  24. response = UserAgent.get(
  25. search_url,
  26. {},
  27. HttpOptions.new(options).build
  28. )
  29. raise Errors::NetworkError.new(self, response.error) if !response.success?
  30. response.data
  31. rescue ArgumentError, URI::InvalidURIError
  32. raise Errors::SearchUrlInvalidError, self
  33. end
  34. def search_url
  35. raise Errors::SearchUrlMissingError, self if options[:search_url].blank?
  36. NotificationFactory::Renderer.new(
  37. objects: @render_context,
  38. template: options[:search_url].gsub("\#{search.term}", @term),
  39. escape: false,
  40. url_encode: true,
  41. ).render(debug_errors: false)
  42. end
  43. def get_items_list(input)
  44. path = options[:search_result_list_key]
  45. array = if path.present?
  46. input.dig(*path.split('.'))
  47. else
  48. input
  49. end
  50. raise TypeError if !array
  51. raise Errors::ListNotArrayParsingError.new(self, path) if !array.is_a?(Array)
  52. array
  53. rescue TypeError
  54. raise Errors::ListPathParsingError.new(self, path)
  55. end
  56. def get_item_value(input)
  57. get_textual_value(:value, input)
  58. end
  59. def get_item_label(input)
  60. get_textual_value(:label, input)
  61. end
  62. def get_textual_value(key, input)
  63. options_key = "search_result_#{key}_key"
  64. path = options[options_key]
  65. value = if path.present?
  66. input.dig(*path.split('.'))
  67. else
  68. input
  69. end
  70. raise TypeError if value.nil?
  71. if [String, Numeric, TrueClass, FalseClass].none? { |elem| value.is_a?(elem) }
  72. raise Errors::ParsingError.class_for(key, :invalid).new(self, path)
  73. end
  74. value
  75. rescue TypeError
  76. raise Errors::ParsingError.class_for(key, :path).new(self, path)
  77. end
  78. end