supportify_client 1.0.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,36 +7,37 @@ require 'uri'
7
7
 
8
8
  module Supportify
9
9
  class ApiClient
10
-
11
- attr_accessor :host
10
+ # The Configuration object holding settings to be used in the API client.
11
+ attr_accessor :config
12
12
 
13
13
  # Defines the headers to be used in HTTP requests of all API calls by default.
14
14
  #
15
15
  # @return [Hash]
16
16
  attr_accessor :default_headers
17
17
 
18
- # Stores the HTTP response from the last API call using this API client.
19
- attr_accessor :last_response
20
-
21
- def initialize(host = nil)
22
- @host = host || Configuration.base_url
23
- @format = 'json'
18
+ def initialize(config = Configuration.default)
19
+ @config = config
24
20
  @user_agent = "ruby-swagger-#{VERSION}"
25
21
  @default_headers = {
26
- 'Content-Type' => "application/#{@format.downcase}",
22
+ 'Content-Type' => "application/json",
27
23
  'User-Agent' => @user_agent
28
24
  }
29
25
  end
30
26
 
27
+ def self.default
28
+ @@default ||= ApiClient.new
29
+ end
30
+
31
+ # Call an API with given options.
32
+ #
33
+ # @return [Array<(Object, Fixnum, Hash)>] an array of 3 elements:
34
+ # the data deserialized from response body (could be nil), response status code and response headers.
31
35
  def call_api(http_method, path, opts = {})
32
36
  request = build_request(http_method, path, opts)
33
37
  response = request.run
34
38
 
35
- # record as last response
36
- @last_response = response
37
-
38
- if Configuration.debugging
39
- Configuration.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n"
39
+ if @config.debugging
40
+ @config.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n"
40
41
  end
41
42
 
42
43
  unless response.success?
@@ -47,10 +48,11 @@ module Supportify
47
48
  end
48
49
 
49
50
  if opts[:return_type]
50
- deserialize(response, opts[:return_type])
51
+ data = deserialize(response, opts[:return_type])
51
52
  else
52
- nil
53
+ data = nil
53
54
  end
55
+ return data, response.code, response.headers
54
56
  end
55
57
 
56
58
  def build_request(http_method, path, opts = {})
@@ -69,22 +71,34 @@ module Supportify
69
71
  :method => http_method,
70
72
  :headers => header_params,
71
73
  :params => query_params,
72
- :ssl_verifypeer => Configuration.verify_ssl,
73
- :cainfo => Configuration.ssl_ca_cert,
74
- :verbose => Configuration.debugging
74
+ :timeout => @config.timeout,
75
+ :ssl_verifypeer => @config.verify_ssl,
76
+ :sslcert => @config.cert_file,
77
+ :sslkey => @config.key_file,
78
+ :cainfo => @config.ssl_ca_cert,
79
+ :verbose => @config.debugging
75
80
  }
76
81
 
77
82
  if [:post, :patch, :put, :delete].include?(http_method)
78
83
  req_body = build_request_body(header_params, form_params, opts[:body])
79
84
  req_opts.update :body => req_body
80
- if Configuration.debugging
81
- Configuration.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n"
85
+ if @config.debugging
86
+ @config.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n"
82
87
  end
83
88
  end
84
89
 
85
90
  Typhoeus::Request.new(url, req_opts)
86
91
  end
87
92
 
93
+ # Check if the given MIME is a JSON MIME.
94
+ # JSON MIME examples:
95
+ # application/json
96
+ # application/json; charset=UTF8
97
+ # APPLICATION/JSON
98
+ def json_mime?(mime)
99
+ !!(mime =~ /\Aapplication\/json(;.*)?\z/i)
100
+ end
101
+
88
102
  # Deserialize the response to the given return type.
89
103
  #
90
104
  # @param [String] return_type some examples: "User", "Array[User]", "Hash[String,Integer]"
@@ -98,9 +112,7 @@ module Supportify
98
112
  # ensuring a default content type
99
113
  content_type = response.headers['Content-Type'] || 'application/json'
100
114
 
101
- unless content_type.start_with?('application/json')
102
- fail "Content-Type is not supported: #{content_type}"
103
- end
115
+ fail "Content-Type is not supported: #{content_type}" unless json_mime?(content_type)
104
116
 
105
117
  begin
106
118
  data = JSON.parse("[#{body}]", :symbolize_names => true)[0]
@@ -158,38 +170,58 @@ module Supportify
158
170
  # from the "Content-Disposition" header if provided, otherwise a random filename.
159
171
  #
160
172
  # @see Configuration#temp_folder_path
161
- # @return [File] the file downloaded
173
+ # @return [Tempfile] the file downloaded
162
174
  def download_file(response)
163
- tmp_file = Tempfile.new '', Configuration.temp_folder_path
164
175
  content_disposition = response.headers['Content-Disposition']
165
176
  if content_disposition
166
177
  filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
167
- path = File.join File.dirname(tmp_file), filename
178
+ prefix = sanitize_filename(filename)
168
179
  else
169
- path = tmp_file.path
180
+ prefix = 'download-'
181
+ end
182
+ prefix = prefix + '-' unless prefix.end_with?('-')
183
+
184
+ tempfile = nil
185
+ encoding = response.body.encoding
186
+ Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding) do |file|
187
+ file.write(response.body)
188
+ tempfile = file
170
189
  end
171
- # close and delete temp file
172
- tmp_file.close!
190
+ @config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\
191
+ "with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file "\
192
+ "will be deleted automatically with GC. It's also recommended to delete the temp file "\
193
+ "explicitly with `tempfile.delete`"
194
+ tempfile
195
+ end
173
196
 
174
- File.open(path, 'w') { |file| file.write(response.body) }
175
- Configuration.logger.info "File written to #{path}. Please move the file to a proper "\
176
- "folder for further processing and delete the temp afterwards"
177
- File.new(path)
197
+ # Sanitize filename by removing path.
198
+ # e.g. ../../sun.gif becomes sun.gif
199
+ #
200
+ # @param [String] filename the filename to be sanitized
201
+ # @return [String] the sanitized filename
202
+ def sanitize_filename(filename)
203
+ filename.gsub /.*[\/\\]/, ''
178
204
  end
179
205
 
180
206
  def build_request_url(path)
181
207
  # Add leading and trailing slashes to path
182
208
  path = "/#{path}".gsub(/\/+/, '/')
183
- URI.encode(host + path)
209
+ URI.encode(@config.base_url + path)
184
210
  end
185
211
 
186
212
  def build_request_body(header_params, form_params, body)
187
213
  # http form
188
214
  if header_params['Content-Type'] == 'application/x-www-form-urlencoded' ||
189
215
  header_params['Content-Type'] == 'multipart/form-data'
190
- data = form_params.dup
191
- data.each do |key, value|
192
- data[key] = value.to_s if value && !value.is_a?(File)
216
+ data = {}
217
+ form_params.each do |key, value|
218
+ case value
219
+ when File, Array, nil
220
+ # let typhoeus handle File, Array and nil parameters
221
+ data[key] = value
222
+ else
223
+ data[key] = value.to_s
224
+ end
193
225
  end
194
226
  elsif body
195
227
  data = body.is_a?(String) ? body : body.to_json
@@ -202,7 +234,7 @@ module Supportify
202
234
  # Update hearder and query params based on authentication settings.
203
235
  def update_params_for_auth!(header_params, query_params, auth_names)
204
236
  Array(auth_names).each do |auth_name|
205
- auth_setting = Configuration.auth_settings[auth_name]
237
+ auth_setting = @config.auth_settings[auth_name]
206
238
  next unless auth_setting
207
239
  case auth_setting[:in]
208
240
  when 'header' then header_params[auth_setting[:key]] = auth_setting[:value]
@@ -221,26 +253,21 @@ module Supportify
221
253
  # @param [Array] accepts array for Accept
222
254
  # @return [String] the Accept header (e.g. application/json)
223
255
  def select_header_accept(accepts)
224
- if accepts.empty?
225
- return
226
- elsif accepts.any?{ |s| s.casecmp('application/json') == 0 }
227
- 'application/json' # look for json data by default
228
- else
229
- accepts.join(',')
230
- end
256
+ return nil if accepts.nil? || accepts.empty?
257
+ # use JSON when present, otherwise use all of the provided
258
+ json_accept = accepts.find { |s| json_mime?(s) }
259
+ return json_accept || accepts.join(',')
231
260
  end
232
261
 
233
262
  # Return Content-Type header based on an array of content types provided.
234
263
  # @param [Array] content_types array for Content-Type
235
264
  # @return [String] the Content-Type header (e.g. application/json)
236
265
  def select_header_content_type(content_types)
237
- if content_types.empty?
238
- 'application/json' # use application/json by default
239
- elsif content_types.any?{ |s| s.casecmp('application/json')==0 }
240
- 'application/json' # use application/json if it's included
241
- else
242
- content_types[0] # otherwise, use the first one
243
- end
266
+ # use application/json by default
267
+ return 'application/json' if content_types.nil? || content_types.empty?
268
+ # use JSON when present, otherwise use the first one
269
+ json_content_type = content_types.find { |s| json_mime?(s) }
270
+ return json_content_type || content_types.first
244
271
  end
245
272
 
246
273
  # Convert object (array, hash, object, etc) to JSON string.
@@ -267,5 +294,25 @@ module Supportify
267
294
  obj
268
295
  end
269
296
  end
297
+
298
+ # Build parameter value according to the given collection format.
299
+ # @param [String] collection_format one of :csv, :ssv, :tsv, :pipes and :multi
300
+ def build_collection_param(param, collection_format)
301
+ case collection_format
302
+ when :csv
303
+ param.join(',')
304
+ when :ssv
305
+ param.join(' ')
306
+ when :tsv
307
+ param.join("\t")
308
+ when :pipes
309
+ param.join('|')
310
+ when :multi
311
+ # return the array directly as typhoeus will handle it as expected
312
+ param
313
+ else
314
+ fail "unknown collection format: #{collection_format.inspect}"
315
+ end
316
+ end
270
317
  end
271
318
  end
@@ -1,14 +1,7 @@
1
1
  require 'uri'
2
- require 'singleton'
3
2
 
4
3
  module Supportify
5
4
  class Configuration
6
-
7
- include Singleton
8
-
9
- # Default api client
10
- attr_accessor :api_client
11
-
12
5
  # Defines url scheme
13
6
  attr_accessor :scheme
14
7
 
@@ -44,6 +37,9 @@ module Supportify
44
37
  # @return [String]
45
38
  attr_accessor :password
46
39
 
40
+ # Defines the access token (Bearer) used with OAuth2.
41
+ attr_accessor :access_token
42
+
47
43
  # Set this to enable/disable debugging. When enabled (set to true), HTTP request/response
48
44
  # details will be logged with `logger.debug` (see the `logger` attribute).
49
45
  # Default to false.
@@ -64,6 +60,11 @@ module Supportify
64
60
  # @return [String]
65
61
  attr_accessor :temp_folder_path
66
62
 
63
+ # The time limit for HTTP request in seconds.
64
+ # Default to 0 (never times out).
65
+ attr_accessor :timeout
66
+
67
+ ### TLS/SSL
67
68
  # Set this to false to skip verifying SSL certificate when calling API from https server.
68
69
  # Default to true.
69
70
  #
@@ -80,36 +81,41 @@ module Supportify
80
81
  # https://github.com/typhoeus/typhoeus/blob/master/lib/typhoeus/easy_factory.rb#L145
81
82
  attr_accessor :ssl_ca_cert
82
83
 
84
+ # Client certificate file (for client certificate)
85
+ attr_accessor :cert_file
86
+
87
+ # Client private key file (for client certificate)
88
+ attr_accessor :key_file
89
+
83
90
  attr_accessor :inject_format
84
91
 
85
92
  attr_accessor :force_ending_format
86
93
 
87
- class << self
88
- def method_missing(method_name, *args, &block)
89
- config = Configuration.instance
90
- if config.respond_to?(method_name)
91
- config.send(method_name, *args, &block)
92
- else
93
- super
94
- end
95
- end
96
- end
97
-
98
94
  def initialize
99
95
  @scheme = 'https'
100
96
  @host = 'api.supportify.io'
101
- @base_path = '/v2'
97
+ @base_path = '/v3'
102
98
  @api_key = {}
103
99
  @api_key_prefix = {}
100
+ @timeout = 0
104
101
  @verify_ssl = true
102
+ @cert_file = nil
103
+ @key_file = nil
105
104
  @debugging = false
106
105
  @inject_format = false
107
106
  @force_ending_format = false
108
107
  @logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
108
+
109
+ yield(self) if block_given?
110
+ end
111
+
112
+ # The default Configuration object.
113
+ def self.default
114
+ @@default ||= Configuration.new
109
115
  end
110
116
 
111
- def api_client
112
- @api_client ||= ApiClient.new
117
+ def configure
118
+ yield(self) if block_given?
113
119
  end
114
120
 
115
121
  def scheme=(scheme)
@@ -129,7 +135,7 @@ module Supportify
129
135
  end
130
136
 
131
137
  def base_url
132
- url = "#{scheme}://#{[host, base_path].join('/').gsub(/\/+/, '/')}"
138
+ url = "#{scheme}://#{[host, base_path].join('/').gsub(/\/+/, '/')}".sub(/\/+\z/, '')
133
139
  URI.encode(url)
134
140
  end
135
141
 
@@ -163,23 +169,23 @@ module Supportify
163
169
  def application_api_key
164
170
  @api_key['X-SUPPORTIFY-APPKEY']
165
171
  end
166
-
172
+
167
173
  # Returns Auth Settings hash for api client.
168
174
  def auth_settings
169
175
  {
170
- 'api_key' =>
176
+ 'app_key' =>
171
177
  {
172
178
  type: 'api_key',
173
179
  in: 'header',
174
- key: 'X-SUPPORTIFY-APIKEY',
175
- value: api_key_with_prefix('X-SUPPORTIFY-APIKEY')
180
+ key: 'X-SUPPORTIFY-APPKEY',
181
+ value: api_key_with_prefix('X-SUPPORTIFY-APPKEY')
176
182
  },
177
- 'app_key' =>
183
+ 'api_key' =>
178
184
  {
179
185
  type: 'api_key',
180
186
  in: 'header',
181
- key: 'X-SUPPORTIFY-APPKEY',
182
- value: api_key_with_prefix('X-SUPPORTIFY-APPKEY')
187
+ key: 'X-SUPPORTIFY-APIKEY',
188
+ value: api_key_with_prefix('X-SUPPORTIFY-APIKEY')
183
189
  },
184
190
  }
185
191
  end
@@ -1,24 +1,30 @@
1
+ require 'date'
2
+
1
3
  module Supportify
2
- #
3
- class Category < BaseObject
4
- attr_accessor :id, :description, :name
5
- # attribute mapping from ruby-style variable name to JSON key
4
+ class Category
5
+ # Unique identifier representing a specific category within an application.
6
+ attr_accessor :id
7
+
8
+ # Description of the category.
9
+ attr_accessor :description
10
+
11
+ # Display name of the category.
12
+ attr_accessor :name
13
+
14
+ # Attribute mapping from ruby-style variable name to JSON key.
6
15
  def self.attribute_map
7
16
  {
8
17
 
9
- # Unique identifier representing a specific category within an application.
10
18
  :'id' => :'id',
11
19
 
12
- # Description of the category.
13
20
  :'description' => :'description',
14
21
 
15
- # Display name of the category.
16
22
  :'name' => :'name'
17
23
 
18
24
  }
19
25
  end
20
26
 
21
- # attribute type
27
+ # Attribute type mapping.
22
28
  def self.swagger_types
23
29
  {
24
30
  :'id' => :'Integer',
@@ -29,7 +35,7 @@ module Supportify
29
35
  end
30
36
 
31
37
  def initialize(attributes = {})
32
- return if !attributes.is_a?(Hash) || attributes.empty?
38
+ return unless attributes.is_a?(Hash)
33
39
 
34
40
  # convert string to symbol for hash key
35
41
  attributes = attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
@@ -49,5 +55,115 @@ module Supportify
49
55
 
50
56
  end
51
57
 
58
+ # Check equality by comparing each attribute.
59
+ def ==(o)
60
+ return true if self.equal?(o)
61
+ self.class == o.class &&
62
+ id == o.id &&
63
+ description == o.description &&
64
+ name == o.name
65
+ end
66
+
67
+ # @see the `==` method
68
+ def eql?(o)
69
+ self == o
70
+ end
71
+
72
+ # Calculate hash code according to all attributes.
73
+ def hash
74
+ [id, description, name].hash
75
+ end
76
+
77
+ # build the object from hash
78
+ def build_from_hash(attributes)
79
+ return nil unless attributes.is_a?(Hash)
80
+ self.class.swagger_types.each_pair do |key, type|
81
+ if type =~ /^Array<(.*)>/i
82
+ if attributes[self.class.attribute_map[key]].is_a?(Array)
83
+ self.send("#{key}=", attributes[self.class.attribute_map[key]].map{ |v| _deserialize($1, v) } )
84
+ else
85
+ #TODO show warning in debug mode
86
+ end
87
+ elsif !attributes[self.class.attribute_map[key]].nil?
88
+ self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
89
+ else
90
+ # data not found in attributes(hash), not an issue as the data can be optional
91
+ end
92
+ end
93
+
94
+ self
95
+ end
96
+
97
+ def _deserialize(type, value)
98
+ case type.to_sym
99
+ when :DateTime
100
+ DateTime.parse(value)
101
+ when :Date
102
+ Date.parse(value)
103
+ when :String
104
+ value.to_s
105
+ when :Integer
106
+ value.to_i
107
+ when :Float
108
+ value.to_f
109
+ when :BOOLEAN
110
+ if value =~ /^(true|t|yes|y|1)$/i
111
+ true
112
+ else
113
+ false
114
+ end
115
+ when /\AArray<(?<inner_type>.+)>\z/
116
+ inner_type = Regexp.last_match[:inner_type]
117
+ value.map { |v| _deserialize(inner_type, v) }
118
+ when /\AHash<(?<k_type>.+), (?<v_type>.+)>\z/
119
+ k_type = Regexp.last_match[:k_type]
120
+ v_type = Regexp.last_match[:v_type]
121
+ {}.tap do |hash|
122
+ value.each do |k, v|
123
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
124
+ end
125
+ end
126
+ else # model
127
+ _model = Supportify.const_get(type).new
128
+ _model.build_from_hash(value)
129
+ end
130
+ end
131
+
132
+ def to_s
133
+ to_hash.to_s
134
+ end
135
+
136
+ # to_body is an alias to to_body (backward compatibility))
137
+ def to_body
138
+ to_hash
139
+ end
140
+
141
+ # return the object in the form of hash
142
+ def to_hash
143
+ hash = {}
144
+ self.class.attribute_map.each_pair do |attr, param|
145
+ value = self.send(attr)
146
+ next if value.nil?
147
+ hash[param] = _to_hash(value)
148
+ end
149
+ hash
150
+ end
151
+
152
+ # Method to output non-array value in the form of hash
153
+ # For object, use to_hash. Otherwise, just return the value
154
+ def _to_hash(value)
155
+ if value.is_a?(Array)
156
+ value.compact.map{ |v| _to_hash(v) }
157
+ elsif value.is_a?(Hash)
158
+ {}.tap do |hash|
159
+ value.each { |k, v| hash[k] = _to_hash(v) }
160
+ end
161
+ elsif value.respond_to? :to_hash
162
+ value.to_hash
163
+ else
164
+ value
165
+ end
166
+ end
167
+
52
168
  end
53
169
  end