123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- class ExternalDataSource
- attr_reader :json, :parsed_items, :options, :term
- def initialize(options:, term:, render_context:, limit: 10)
- @term = term
- @options = options
- @limit = limit
- @render_context = render_context
- end
- def process
- @json = fetch_json
- @parsed_items = get_items_list(@json)
- @parsed_items
- .slice(...@limit)
- .map do |elem|
- {
- value: get_item_value(elem),
- label: get_item_label(elem)
- }
- end
- end
- private
- def fetch_json
- response = UserAgent.get(
- search_url,
- {},
- HttpOptions.new(options).build
- )
- raise Errors::NetworkError.new(self, response.error) if !response.success?
- response.data
- rescue ArgumentError, URI::InvalidURIError
- raise Errors::SearchUrlInvalidError, self
- end
- def search_url
- raise Errors::SearchUrlMissingError, self if options[:search_url].blank?
- NotificationFactory::Renderer.new(
- objects: {
- **@render_context,
- # Extend the render context with the current object instance.
- # This will allow for usage of `search.term` in the search URL, as this property is readily available here.
- # Only this approach will guarantee that the template variable is replaced with a properly URL encoded value.
- # https://github.com/zammad/zammad/issues/4980
- search: self,
- },
- template: options[:search_url],
- escape: false,
- url_encode: true,
- ).render(debug_errors: false)
- end
- def get_items_list(input)
- path = options[:search_result_list_key]
- array = if path.present?
- input.dig(*path.split('.'))
- else
- input
- end
- raise TypeError if !array
- raise Errors::ListNotArrayParsingError.new(self, path) if !array.is_a?(Array)
- array
- rescue TypeError
- raise Errors::ListPathParsingError.new(self, path)
- end
- def get_item_value(input)
- get_textual_value(:value, input)
- end
- def get_item_label(input)
- get_textual_value(:label, input)
- end
- def get_textual_value(key, input)
- options_key = "search_result_#{key}_key"
- path = options[options_key]
- value = if path.present?
- input.dig(*path.split('.'))
- else
- input
- end
- raise TypeError if value.nil?
- if [String, Numeric, TrueClass, FalseClass].none? { |elem| value.is_a?(elem) }
- raise Errors::ParsingError.class_for(key, :invalid).new(self, path)
- end
- value
- rescue TypeError
- raise Errors::ParsingError.class_for(key, :path).new(self, path)
- end
- end
|