supportify_client 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -4
  3. data/Gemfile.lock +47 -39
  4. data/Rakefile +4 -4
  5. data/VERSION +1 -1
  6. data/lib/supportify_client/api/supportify_api.rb +560 -0
  7. data/lib/supportify_client/api_client.rb +271 -0
  8. data/lib/supportify_client/api_error.rb +24 -0
  9. data/lib/supportify_client/configuration.rb +187 -0
  10. data/lib/supportify_client/models/base_object.rb +87 -0
  11. data/lib/supportify_client/models/category.rb +53 -0
  12. data/lib/supportify_client/models/error.rb +53 -0
  13. data/lib/supportify_client/models/faq.rb +161 -0
  14. data/lib/supportify_client/models/info.rb +45 -0
  15. data/lib/supportify_client/models/tag.rb +53 -0
  16. data/lib/supportify_client/models/user.rb +45 -0
  17. data/lib/supportify_client.rb +30 -14
  18. data/spec/features/.gitkeep +0 -0
  19. data/supportify_client.gemspec +27 -27
  20. metadata +38 -26
  21. data/lib/supportify_client/api/category.rb +0 -17
  22. data/lib/supportify_client/api/error.rb +0 -13
  23. data/lib/supportify_client/api/faq.rb +0 -23
  24. data/lib/supportify_client/api/search.rb +0 -9
  25. data/lib/supportify_client/api/tag.rb +0 -17
  26. data/lib/supportify_client/api.rb +0 -5
  27. data/lib/supportify_client/client.rb +0 -49
  28. data/lib/supportify_client/factory.rb +0 -29
  29. data/lib/supportify_client/gateway.rb +0 -32
  30. data/lib/supportify_client/repository.rb +0 -23
  31. data/spec/features/categories_spec.rb +0 -55
  32. data/spec/features/client_spec.rb +0 -50
  33. data/spec/features/errors_spec.rb +0 -96
  34. data/spec/features/faqs_spec.rb +0 -55
  35. data/spec/features/search_spec.rb +0 -29
  36. data/spec/features/tags_spec.rb +0 -55
@@ -0,0 +1,271 @@
1
+ require 'date'
2
+ require 'json'
3
+ require 'logger'
4
+ require 'tempfile'
5
+ require 'typhoeus'
6
+ require 'uri'
7
+
8
+ module Supportify
9
+ class ApiClient
10
+
11
+ attr_accessor :host
12
+
13
+ # Defines the headers to be used in HTTP requests of all API calls by default.
14
+ #
15
+ # @return [Hash]
16
+ attr_accessor :default_headers
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'
24
+ @user_agent = "ruby-swagger-#{VERSION}"
25
+ @default_headers = {
26
+ 'Content-Type' => "application/#{@format.downcase}",
27
+ 'User-Agent' => @user_agent
28
+ }
29
+ end
30
+
31
+ def call_api(http_method, path, opts = {})
32
+ request = build_request(http_method, path, opts)
33
+ response = request.run
34
+
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"
40
+ end
41
+
42
+ unless response.success?
43
+ fail ApiError.new(:code => response.code,
44
+ :response_headers => response.headers,
45
+ :response_body => response.body),
46
+ response.status_message
47
+ end
48
+
49
+ if opts[:return_type]
50
+ deserialize(response, opts[:return_type])
51
+ else
52
+ nil
53
+ end
54
+ end
55
+
56
+ def build_request(http_method, path, opts = {})
57
+ url = build_request_url(path)
58
+ http_method = http_method.to_sym.downcase
59
+
60
+ header_params = @default_headers.merge(opts[:header_params] || {})
61
+ query_params = opts[:query_params] || {}
62
+ form_params = opts[:form_params] || {}
63
+
64
+
65
+ update_params_for_auth! header_params, query_params, opts[:auth_names]
66
+
67
+
68
+ req_opts = {
69
+ :method => http_method,
70
+ :headers => header_params,
71
+ :params => query_params,
72
+ :ssl_verifypeer => Configuration.verify_ssl,
73
+ :cainfo => Configuration.ssl_ca_cert,
74
+ :verbose => Configuration.debugging
75
+ }
76
+
77
+ if [:post, :patch, :put, :delete].include?(http_method)
78
+ req_body = build_request_body(header_params, form_params, opts[:body])
79
+ 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"
82
+ end
83
+ end
84
+
85
+ Typhoeus::Request.new(url, req_opts)
86
+ end
87
+
88
+ # Deserialize the response to the given return type.
89
+ #
90
+ # @param [String] return_type some examples: "User", "Array[User]", "Hash[String,Integer]"
91
+ def deserialize(response, return_type)
92
+ body = response.body
93
+ return nil if body.nil? || body.empty?
94
+
95
+ # handle file downloading - save response body into a tmp file and return the File instance
96
+ return download_file(response) if return_type == 'File'
97
+
98
+ # ensuring a default content type
99
+ content_type = response.headers['Content-Type'] || 'application/json'
100
+
101
+ unless content_type.start_with?('application/json')
102
+ fail "Content-Type is not supported: #{content_type}"
103
+ end
104
+
105
+ begin
106
+ data = JSON.parse("[#{body}]", :symbolize_names => true)[0]
107
+ rescue JSON::ParserError => e
108
+ if %w(String Date DateTime).include?(return_type)
109
+ data = body
110
+ else
111
+ raise e
112
+ end
113
+ end
114
+
115
+ convert_to_type data, return_type
116
+ end
117
+
118
+ # Convert data to the given return type.
119
+ def convert_to_type(data, return_type)
120
+ return nil if data.nil?
121
+ case return_type
122
+ when 'String'
123
+ data.to_s
124
+ when 'Integer'
125
+ data.to_i
126
+ when 'Float'
127
+ data.to_f
128
+ when 'BOOLEAN'
129
+ data == true
130
+ when 'DateTime'
131
+ # parse date time (expecting ISO 8601 format)
132
+ DateTime.parse data
133
+ when 'Date'
134
+ # parse date time (expecting ISO 8601 format)
135
+ Date.parse data
136
+ when 'Object'
137
+ # generic object, return directly
138
+ data
139
+ when /\AArray<(.+)>\z/
140
+ # e.g. Array<Pet>
141
+ sub_type = $1
142
+ data.map {|item| convert_to_type(item, sub_type) }
143
+ when /\AHash\<String, (.+)\>\z/
144
+ # e.g. Hash<String, Integer>
145
+ sub_type = $1
146
+ {}.tap do |hash|
147
+ data.each {|k, v| hash[k] = convert_to_type(v, sub_type) }
148
+ end
149
+ else
150
+ # models, e.g. Pet
151
+ Supportify.const_get(return_type).new.tap do |model|
152
+ model.build_from_hash data
153
+ end
154
+ end
155
+ end
156
+
157
+ # Save response body into a file in (the defined) temporary folder, using the filename
158
+ # from the "Content-Disposition" header if provided, otherwise a random filename.
159
+ #
160
+ # @see Configuration#temp_folder_path
161
+ # @return [File] the file downloaded
162
+ def download_file(response)
163
+ tmp_file = Tempfile.new '', Configuration.temp_folder_path
164
+ content_disposition = response.headers['Content-Disposition']
165
+ if content_disposition
166
+ filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
167
+ path = File.join File.dirname(tmp_file), filename
168
+ else
169
+ path = tmp_file.path
170
+ end
171
+ # close and delete temp file
172
+ tmp_file.close!
173
+
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)
178
+ end
179
+
180
+ def build_request_url(path)
181
+ # Add leading and trailing slashes to path
182
+ path = "/#{path}".gsub(/\/+/, '/')
183
+ URI.encode(host + path)
184
+ end
185
+
186
+ def build_request_body(header_params, form_params, body)
187
+ # http form
188
+ if header_params['Content-Type'] == 'application/x-www-form-urlencoded' ||
189
+ 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)
193
+ end
194
+ elsif body
195
+ data = body.is_a?(String) ? body : body.to_json
196
+ else
197
+ data = nil
198
+ end
199
+ data
200
+ end
201
+
202
+ # Update hearder and query params based on authentication settings.
203
+ def update_params_for_auth!(header_params, query_params, auth_names)
204
+ Array(auth_names).each do |auth_name|
205
+ auth_setting = Configuration.auth_settings[auth_name]
206
+ next unless auth_setting
207
+ case auth_setting[:in]
208
+ when 'header' then header_params[auth_setting[:key]] = auth_setting[:value]
209
+ when 'query' then query_params[auth_setting[:key]] = auth_setting[:value]
210
+ else fail ArgumentError, 'Authentication token must be in `query` of `header`'
211
+ end
212
+ end
213
+ end
214
+
215
+ def user_agent=(user_agent)
216
+ @user_agent = user_agent
217
+ @default_headers['User-Agent'] = @user_agent
218
+ end
219
+
220
+ # Return Accept header based on an array of accepts provided.
221
+ # @param [Array] accepts array for Accept
222
+ # @return [String] the Accept header (e.g. application/json)
223
+ 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
231
+ end
232
+
233
+ # Return Content-Type header based on an array of content types provided.
234
+ # @param [Array] content_types array for Content-Type
235
+ # @return [String] the Content-Type header (e.g. application/json)
236
+ 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
244
+ end
245
+
246
+ # Convert object (array, hash, object, etc) to JSON string.
247
+ # @param [Object] model object to be converted into JSON string
248
+ # @return [String] JSON string representation of the object
249
+ def object_to_http_body(model)
250
+ return if model.nil?
251
+ _body = nil
252
+ if model.is_a?(Array)
253
+ _body = model.map{|m| object_to_hash(m) }
254
+ else
255
+ _body = object_to_hash(model)
256
+ end
257
+ _body.to_json
258
+ end
259
+
260
+ # Convert object(non-array) to hash.
261
+ # @param [Object] obj object to be converted into JSON string
262
+ # @return [String] JSON string representation of the object
263
+ def object_to_hash(obj)
264
+ if obj.respond_to?(:to_hash)
265
+ obj.to_hash
266
+ else
267
+ obj
268
+ end
269
+ end
270
+ end
271
+ end
@@ -0,0 +1,24 @@
1
+ module Supportify
2
+ class ApiError < StandardError
3
+ attr_reader :code, :response_headers, :response_body
4
+
5
+ # Usage examples:
6
+ # ApiError.new
7
+ # ApiError.new("message")
8
+ # ApiError.new(:code => 500, :response_headers => {}, :response_body => "")
9
+ # ApiError.new(:code => 404, :message => "Not Found")
10
+ def initialize(arg = nil)
11
+ if arg.is_a? Hash
12
+ arg.each do |k, v|
13
+ if k.to_s == 'message'
14
+ super v
15
+ else
16
+ instance_variable_set "@#{k}", v
17
+ end
18
+ end
19
+ else
20
+ super arg
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,187 @@
1
+ require 'uri'
2
+ require 'singleton'
3
+
4
+ module Supportify
5
+ class Configuration
6
+
7
+ include Singleton
8
+
9
+ # Default api client
10
+ attr_accessor :api_client
11
+
12
+ # Defines url scheme
13
+ attr_accessor :scheme
14
+
15
+ # Defines url host
16
+ attr_accessor :host
17
+
18
+ # Defines url base path
19
+ attr_accessor :base_path
20
+
21
+ # Defines API keys used with API Key authentications.
22
+ #
23
+ # @return [Hash] key: parameter name, value: parameter value (API key)
24
+ #
25
+ # @example parameter name is "api_key", API key is "xxx" (e.g. "api_key=xxx" in query string)
26
+ # config.api_key['api_key'] = 'xxx'
27
+ attr_accessor :api_key
28
+
29
+ # Defines API key prefixes used with API Key authentications.
30
+ #
31
+ # @return [Hash] key: parameter name, value: API key prefix
32
+ #
33
+ # @example parameter name is "Authorization", API key prefix is "Token" (e.g. "Authorization: Token xxx" in headers)
34
+ # config.api_key_prefix['api_key'] = 'Token'
35
+ attr_accessor :api_key_prefix
36
+
37
+ # Defines the username used with HTTP basic authentication.
38
+ #
39
+ # @return [String]
40
+ attr_accessor :username
41
+
42
+ # Defines the password used with HTTP basic authentication.
43
+ #
44
+ # @return [String]
45
+ attr_accessor :password
46
+
47
+ # Set this to enable/disable debugging. When enabled (set to true), HTTP request/response
48
+ # details will be logged with `logger.debug` (see the `logger` attribute).
49
+ # Default to false.
50
+ #
51
+ # @return [true, false]
52
+ attr_accessor :debugging
53
+
54
+ # Defines the logger used for debugging.
55
+ # Default to `Rails.logger` (when in Rails) or logging to STDOUT.
56
+ #
57
+ # @return [#debug]
58
+ attr_accessor :logger
59
+
60
+ # Defines the temporary folder to store downloaded files
61
+ # (for API endpoints that have file response).
62
+ # Default to use `Tempfile`.
63
+ #
64
+ # @return [String]
65
+ attr_accessor :temp_folder_path
66
+
67
+ # Set this to false to skip verifying SSL certificate when calling API from https server.
68
+ # Default to true.
69
+ #
70
+ # @note Do NOT set it to false in production code, otherwise you would face multiple types of cryptographic attacks.
71
+ #
72
+ # @return [true, false]
73
+ attr_accessor :verify_ssl
74
+
75
+ # Set this to customize the certificate file to verify the peer.
76
+ #
77
+ # @return [String] the path to the certificate file
78
+ #
79
+ # @see The `cainfo` option of Typhoeus, `--cert` option of libcurl. Related source code:
80
+ # https://github.com/typhoeus/typhoeus/blob/master/lib/typhoeus/easy_factory.rb#L145
81
+ attr_accessor :ssl_ca_cert
82
+
83
+ attr_accessor :inject_format
84
+
85
+ attr_accessor :force_ending_format
86
+
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
+ def initialize
99
+ @scheme = 'https'
100
+ @host = 'api.supportify.io'
101
+ @base_path = '/v2'
102
+ @api_key = {}
103
+ @api_key_prefix = {}
104
+ @verify_ssl = true
105
+ @debugging = false
106
+ @inject_format = false
107
+ @force_ending_format = false
108
+ @logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
109
+ end
110
+
111
+ def api_client
112
+ @api_client ||= ApiClient.new
113
+ end
114
+
115
+ def scheme=(scheme)
116
+ # remove :// from scheme
117
+ @scheme = scheme.sub(/:\/\//, '')
118
+ end
119
+
120
+ def host=(host)
121
+ # remove http(s):// and anything after a slash
122
+ @host = host.sub(/https?:\/\//, '').split('/').first
123
+ end
124
+
125
+ def base_path=(base_path)
126
+ # Add leading and trailing slashes to base_path
127
+ @base_path = "/#{base_path}".gsub(/\/+/, '/')
128
+ @base_path = "" if @base_path == "/"
129
+ end
130
+
131
+ def base_url
132
+ url = "#{scheme}://#{[host, base_path].join('/').gsub(/\/+/, '/')}"
133
+ URI.encode(url)
134
+ end
135
+
136
+ # Gets API key (with prefix if set).
137
+ # @param [String] param_name the parameter name of API key auth
138
+ def api_key_with_prefix(param_name)
139
+ if @api_key_prefix[param_name]
140
+ "#{@api_key_prefix[param_name]} #{@api_key[param_name]}"
141
+ else
142
+ @api_key[param_name]
143
+ end
144
+ end
145
+
146
+ # Gets Basic Auth token string
147
+ def basic_auth_token
148
+ 'Basic ' + ["#{username}:#{password}"].pack('m').delete("\r\n")
149
+ end
150
+
151
+ def account_api_key=(value)
152
+ @api_key['X-SUPPORTIFY-APIKEY'] = value
153
+ end
154
+
155
+ def account_api_key
156
+ @api_key['X-SUPPORTIFY-APIKEY']
157
+ end
158
+
159
+ def application_api_key=(value)
160
+ @api_key['X-SUPPORTIFY-APPKEY'] = value
161
+ end
162
+
163
+ def application_api_key
164
+ @api_key['X-SUPPORTIFY-APPKEY']
165
+ end
166
+
167
+ # Returns Auth Settings hash for api client.
168
+ def auth_settings
169
+ {
170
+ 'api_key' =>
171
+ {
172
+ type: 'api_key',
173
+ in: 'header',
174
+ key: 'X-SUPPORTIFY-APIKEY',
175
+ value: api_key_with_prefix('X-SUPPORTIFY-APIKEY')
176
+ },
177
+ 'app_key' =>
178
+ {
179
+ type: 'api_key',
180
+ in: 'header',
181
+ key: 'X-SUPPORTIFY-APPKEY',
182
+ value: api_key_with_prefix('X-SUPPORTIFY-APPKEY')
183
+ },
184
+ }
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,87 @@
1
+ require 'date'
2
+
3
+ module Supportify
4
+ # base class containing fundamental method such as to_hash, build_from_hash and more
5
+ class BaseObject
6
+
7
+ # build the object from hash
8
+ def build_from_hash(attributes)
9
+ return nil unless attributes.is_a?(Hash)
10
+ self.class.swagger_types.each_pair do |key, type|
11
+ if type =~ /^Array<(.*)>/i
12
+ if attributes[self.class.attribute_map[key]].is_a?(Array)
13
+ self.send("#{key}=", attributes[self.class.attribute_map[key]].map{ |v| _deserialize($1, v) } )
14
+ else
15
+ #TODO show warning in debug mode
16
+ end
17
+ elsif !attributes[self.class.attribute_map[key]].nil?
18
+ self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
19
+ else
20
+ # data not found in attributes(hash), not an issue as the data can be optional
21
+ end
22
+ end
23
+
24
+ self
25
+ end
26
+
27
+ def _deserialize(type, value)
28
+ case type.to_sym
29
+ when :DateTime
30
+ DateTime.parse(value)
31
+ when :Date
32
+ Date.parse(value)
33
+ when :String
34
+ value.to_s
35
+ when :Integer
36
+ value.to_i
37
+ when :Float
38
+ value.to_f
39
+ when :BOOLEAN
40
+ if value =~ /^(true|t|yes|y|1)$/i
41
+ true
42
+ else
43
+ false
44
+ end
45
+ else # model
46
+ _model = Supportify.const_get(type).new
47
+ _model.build_from_hash(value)
48
+ end
49
+ end
50
+
51
+ def to_s
52
+ to_hash.to_s
53
+ end
54
+
55
+ # to_body is an alias to to_body (backward compatibility))
56
+ def to_body
57
+ to_hash
58
+ end
59
+
60
+ # return the object in the form of hash
61
+ def to_hash
62
+ hash = {}
63
+ self.class.attribute_map.each_pair do |key, value|
64
+ if self.send(key).is_a?(Array)
65
+ next if self.send(key).empty?
66
+ hash[value] = self.send(key).select{|v| !v.nil?}.map{ |v| _to_hash v} unless self.send(key).nil?
67
+ else
68
+ unless (_tmp_value = _to_hash self.send(key)).nil?
69
+ hash[value] = _tmp_value
70
+ end
71
+ end
72
+ end
73
+ hash
74
+ end
75
+
76
+ # Method to output non-array value in the form of hash
77
+ # For object, use to_hash. Otherwise, just return the value
78
+ def _to_hash(value)
79
+ if value.respond_to? :to_hash
80
+ value.to_hash
81
+ else
82
+ value
83
+ end
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,53 @@
1
+ module Supportify
2
+ #
3
+ class Category < BaseObject
4
+ attr_accessor :id, :description, :name
5
+ # attribute mapping from ruby-style variable name to JSON key
6
+ def self.attribute_map
7
+ {
8
+
9
+ # Unique identifier representing a specific category within an application.
10
+ :'id' => :'id',
11
+
12
+ # Description of the category.
13
+ :'description' => :'description',
14
+
15
+ # Display name of the category.
16
+ :'name' => :'name'
17
+
18
+ }
19
+ end
20
+
21
+ # attribute type
22
+ def self.swagger_types
23
+ {
24
+ :'id' => :'Integer',
25
+ :'description' => :'String',
26
+ :'name' => :'String'
27
+
28
+ }
29
+ end
30
+
31
+ def initialize(attributes = {})
32
+ return if !attributes.is_a?(Hash) || attributes.empty?
33
+
34
+ # convert string to symbol for hash key
35
+ attributes = attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
36
+
37
+
38
+ if attributes[:'id']
39
+ self.id = attributes[:'id']
40
+ end
41
+
42
+ if attributes[:'description']
43
+ self.description = attributes[:'description']
44
+ end
45
+
46
+ if attributes[:'name']
47
+ self.name = attributes[:'name']
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,53 @@
1
+ module Supportify
2
+ #
3
+ class Error < BaseObject
4
+ attr_accessor :code, :short_description, :long_description
5
+ # attribute mapping from ruby-style variable name to JSON key
6
+ def self.attribute_map
7
+ {
8
+
9
+ # An HTTP error code.
10
+ :'code' => :'code',
11
+
12
+ # A short keyword describing the error that occurred.
13
+ :'short_description' => :'short_description',
14
+
15
+ # A more detailed description of the cause of the error.
16
+ :'long_description' => :'long_description'
17
+
18
+ }
19
+ end
20
+
21
+ # attribute type
22
+ def self.swagger_types
23
+ {
24
+ :'code' => :'Integer',
25
+ :'short_description' => :'String',
26
+ :'long_description' => :'String'
27
+
28
+ }
29
+ end
30
+
31
+ def initialize(attributes = {})
32
+ return if !attributes.is_a?(Hash) || attributes.empty?
33
+
34
+ # convert string to symbol for hash key
35
+ attributes = attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
36
+
37
+
38
+ if attributes[:'code']
39
+ self.code = attributes[:'code']
40
+ end
41
+
42
+ if attributes[:'short_description']
43
+ self.short_description = attributes[:'short_description']
44
+ end
45
+
46
+ if attributes[:'long_description']
47
+ self.long_description = attributes[:'long_description']
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+ end