requester.rb 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. module Import
  2. module OTRS
  3. # @!attribute [rw] retry_sleep
  4. # @return [Number] the sleep time between the request retries
  5. module Requester
  6. extend Import::Helper
  7. # rubocop:disable Style/ModuleFunction
  8. extend self
  9. attr_accessor :retry_sleep
  10. # Loads entries of the given object.
  11. #
  12. # @param object [String] the name of OTRS object
  13. # @param [Hash] opts the options to load entries.
  14. # @option opts [String] :limit the maximum amount of entries that should get loaded
  15. # @option opts [String] :offset the offset where the entry listing should start
  16. # @option opts [Boolean] :diff request only changed/added entries since the last import
  17. #
  18. # @example
  19. # Import::OTRS::Requester.load('State', offset: '0', limit: '50')
  20. # #=> [{'Name':'pending reminder', ...}, ...]
  21. #
  22. # @return [Array<Hash{String => String, Number, nil, Hash, Array}>]
  23. def load(object, opts = {})
  24. @cache ||= {}
  25. if opts.empty? && @cache[object]
  26. return @cache[object]
  27. end
  28. result = request_result(
  29. Subaction: 'Export',
  30. Object: object,
  31. Limit: opts[:limit] || '',
  32. Offset: opts[:offset] || '',
  33. Diff: opts[:diff] ? 1 : 0
  34. )
  35. return result if !opts.empty?
  36. @cache[object] = result
  37. @cache[object]
  38. end
  39. # Lists the OTRS objects and their amount of importable entries.
  40. #
  41. # @example
  42. # Import::OTRS::Requester.list #=> {'DynamicFields' => 5, ...}
  43. #
  44. # @return [Hash{String => Number}] key = OTRS object, value = amount
  45. def list
  46. request_result(Subaction: 'List')
  47. end
  48. # Checks if the connection to the OTRS export endpoint works.
  49. #
  50. # @todo Refactor to something like .connected?
  51. #
  52. # @example
  53. # Import::OTRS::Requester.connection_test #=> true
  54. #
  55. # @raise [RuntimeError] if the API key is not valid
  56. #
  57. # @return [true] always returns true
  58. def connection_test
  59. result = request_json({})
  60. raise 'API key not valid!' if !result['Success']
  61. true
  62. end
  63. private
  64. def request_result(params)
  65. tries ||= 1
  66. response = request_json(params)
  67. response['Result']
  68. rescue
  69. # stop after 3 tries
  70. raise if tries == 3
  71. # try again
  72. tries += 1
  73. sleep tries * (retry_sleep || 15)
  74. retry
  75. end
  76. def request_json(params)
  77. response = post(params)
  78. result = handle_response(response)
  79. raise 'Invalid response' if !result
  80. result
  81. end
  82. def handle_response(response)
  83. encoded_body = Encode.conv('utf8', response.body.to_s)
  84. # remove null bytes otherwise PostgreSQL will fail
  85. encoded_body.gsub!('\u0000', '')
  86. JSON.parse(encoded_body)
  87. end
  88. def post(params)
  89. url = Setting.get('import_otrs_endpoint')
  90. params[:Action] = 'ZammadMigrator'
  91. params[:Key] = Setting.get('import_otrs_endpoint_key')
  92. log 'POST: ' + url
  93. log 'PARAMS: ' + params.inspect
  94. response = UserAgent.post(
  95. url,
  96. params,
  97. {
  98. open_timeout: 10,
  99. read_timeout: 120,
  100. total_timeout: 360,
  101. user: Setting.get('import_otrs_user'),
  102. password: Setting.get('import_otrs_password'),
  103. },
  104. )
  105. if !response
  106. raise "Can't connect to Zammad Migrator"
  107. end
  108. if !response.success?
  109. log "ERROR: #{response.error}"
  110. raise 'Zammad Migrator returned an error'
  111. end
  112. response
  113. end
  114. end
  115. end
  116. end