desk_api 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +27 -0
  3. data/README.md +97 -61
  4. data/lib/desk.rb +29 -1
  5. data/lib/desk_api.rb +57 -5
  6. data/lib/desk_api/client.rb +104 -47
  7. data/lib/desk_api/configuration.rb +201 -108
  8. data/lib/desk_api/default.rb +109 -52
  9. data/lib/desk_api/error.rb +90 -40
  10. data/lib/desk_api/error/bad_gateway.rb +29 -1
  11. data/lib/desk_api/error/bad_request.rb +29 -1
  12. data/lib/desk_api/error/client_error.rb +31 -2
  13. data/lib/desk_api/error/configuration_error.rb +29 -1
  14. data/lib/desk_api/error/conflict.rb +29 -1
  15. data/lib/desk_api/error/follow_redirect_error.rb +42 -0
  16. data/lib/desk_api/error/forbidden.rb +29 -1
  17. data/lib/desk_api/error/gateway_timeout.rb +29 -1
  18. data/lib/desk_api/error/internal_server_error.rb +29 -1
  19. data/lib/desk_api/error/method_not_allowed.rb +29 -1
  20. data/lib/desk_api/error/not_acceptable.rb +29 -1
  21. data/lib/desk_api/error/not_found.rb +29 -1
  22. data/lib/desk_api/error/parser_error.rb +29 -1
  23. data/lib/desk_api/error/server_error.rb +29 -1
  24. data/lib/desk_api/error/service_unavailable.rb +29 -1
  25. data/lib/desk_api/error/too_many_requests.rb +29 -1
  26. data/lib/desk_api/error/unauthorized.rb +29 -1
  27. data/lib/desk_api/error/unprocessable_entity.rb +29 -1
  28. data/lib/desk_api/error/unsupported_media_type.rb +29 -1
  29. data/lib/desk_api/rate_limit.rb +63 -21
  30. data/lib/desk_api/request/encode_json.rb +49 -7
  31. data/lib/desk_api/request/oauth.rb +62 -14
  32. data/lib/desk_api/request/retry.rb +108 -34
  33. data/lib/desk_api/resource.rb +402 -192
  34. data/lib/desk_api/response/follow_redirects.rb +99 -0
  35. data/lib/desk_api/response/parse_dates.rb +63 -21
  36. data/lib/desk_api/response/parse_json.rb +47 -5
  37. data/lib/desk_api/response/raise_error.rb +51 -10
  38. data/lib/desk_api/version.rb +30 -2
  39. data/spec/cassettes/DeskApi_Resource/_update/can_handle_action_params.yml +110 -104
  40. data/spec/cassettes/DeskApi_Resource/_update/can_handle_links.yml +426 -0
  41. data/spec/desk_api/client_spec.rb +28 -0
  42. data/spec/desk_api/configuration_spec.rb +28 -0
  43. data/spec/desk_api/default_spec.rb +28 -0
  44. data/spec/desk_api/error_spec.rb +29 -1
  45. data/spec/desk_api/rate_limit_spec.rb +28 -0
  46. data/spec/desk_api/request/encode_json_spec.rb +28 -0
  47. data/spec/desk_api/request/oauth_spec.rb +28 -0
  48. data/spec/desk_api/request/retry_spec.rb +29 -1
  49. data/spec/desk_api/resource_spec.rb +49 -12
  50. data/spec/desk_api/response/follow_redirects_spec.rb +95 -0
  51. data/spec/desk_api/response/parse_dates_spec.rb +28 -0
  52. data/spec/desk_api/response/parse_json_spec.rb +56 -9
  53. data/spec/desk_api/response/raise_error_spec.rb +28 -0
  54. data/spec/desk_api_spec.rb +28 -0
  55. data/spec/spec_helper.rb +28 -0
  56. metadata +84 -24
  57. data/LICENSE +0 -7
@@ -1,3 +1,31 @@
1
+ # Copyright (c) 2013-2014, Salesforce.com, Inc.
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification,
5
+ # are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of Salesforce.com nor the names of its contributors may be
15
+ # used to endorse or promote products derived from this software without
16
+ # specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22
+ # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25
+ # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
1
29
  require 'faraday'
2
30
 
3
31
  require 'desk_api/default'
@@ -7,141 +35,206 @@ require 'desk_api/request/encode_json'
7
35
  require 'desk_api/response/parse_dates'
8
36
  require 'desk_api/response/parse_json'
9
37
  require 'desk_api/response/raise_error'
38
+ require 'desk_api/response/follow_redirects'
10
39
  require 'desk_api/error/configuration_error'
11
40
  require 'desk_api/error/client_error'
12
41
  require 'desk_api/error/server_error'
13
42
 
14
- module DeskApi::Configuration
15
- extend Forwardable
16
- attr_writer :consumer_secret, :token, :token_secret, :password
17
- attr_accessor :consumer_key, :username, :endpoint, :subdomain, :connection_options, :middleware
18
- def_delegator :options, :hash
19
-
20
- class << self
21
- def keys
22
- @keys ||= [
23
- :consumer_key,
24
- :consumer_secret,
25
- :token,
26
- :token_secret,
27
- :username,
28
- :password,
29
- :subdomain,
30
- :endpoint,
31
- :connection_options
32
- ]
33
- end
34
-
35
- def included(base)
36
- if Gem::Version.new(Faraday::VERSION) >= Gem::Version.new('0.9.0')
37
- Faraday::Request.register_middleware desk_encode_json: DeskApi::Request::EncodeJson
38
- Faraday::Request.register_middleware desk_oauth: DeskApi::Request::OAuth
39
- Faraday::Request.register_middleware desk_retry: DeskApi::Request::Retry
40
- Faraday::Response.register_middleware desk_parse_dates: DeskApi::Response::ParseDates
41
- Faraday::Response.register_middleware desk_parse_json: DeskApi::Response::ParseJson
42
- Faraday::Response.register_middleware desk_raise_error: DeskApi::Response::RaiseError
43
- else
44
- Faraday.register_middleware :request, desk_encode_json: DeskApi::Request::EncodeJson
45
- Faraday.register_middleware :request, desk_oauth: DeskApi::Request::OAuth
46
- Faraday.register_middleware :request, desk_retry: DeskApi::Request::Retry
47
- Faraday.register_middleware :response, desk_parse_dates: DeskApi::Response::ParseDates
48
- Faraday.register_middleware :response, desk_parse_json: DeskApi::Response::ParseJson
49
- Faraday.register_middleware :response, desk_raise_error: DeskApi::Response::RaiseError
43
+ module DeskApi
44
+ # {DeskApi::Configuration} allows to configure a {DeskApi::Client}.
45
+ # It exposes all available configuration options to the client and
46
+ # makes sure secrets are only readable by the client.
47
+ #
48
+ # @author Thomas Stachl <tstachl@salesforce.com>
49
+ # @copyright Copyright (c) 2013-2014 Salesforce.com
50
+ # @license BSD 3-Clause License
51
+ module Configuration
52
+ extend Forwardable
53
+ attr_writer :consumer_secret, :token, :token_secret, :password
54
+ attr_accessor :consumer_key, :username, :endpoint, :subdomain, \
55
+ :connection_options, :middleware
56
+ def_delegator :options, :hash
57
+
58
+ class << self
59
+ # Returns an array of possible configuration options.
60
+ #
61
+ # @return [Array]
62
+ def keys
63
+ @keys ||= [
64
+ :consumer_key, :consumer_secret, :token, :token_secret,
65
+ :username, :password,
66
+ :subdomain, :endpoint,
67
+ :connection_options
68
+ ]
50
69
  end
51
- end
52
- end
53
-
54
- # if subdomain is set make sure endpoint is correct
55
- def endpoint
56
- @endpoint ||= "https://#{@subdomain}.desk.com"
57
- end
58
70
 
59
- def middleware
60
- @middleware ||= Proc.new do |builder|
61
- builder.request :desk_encode_json
62
- builder.request :basic_auth, @username, @password if basic_auth.values.all?
63
- builder.request :desk_oauth, oauth if oauth.values.all?
64
- builder.request :desk_retry
65
-
66
- builder.response :desk_parse_dates
67
- builder.response :desk_raise_error, DeskApi::Error::ClientError
68
- builder.response :desk_raise_error, DeskApi::Error::ServerError
69
- builder.response :desk_parse_json
71
+ # Allows to register middleware for Faraday v0.8 and v0.9
72
+ #
73
+ # @param type [Symbol] either :request or :response
74
+ # @param sym [Symbol] the symbol to register the middleware as
75
+ # @param cls [Symbol] the class name of the middleware
76
+ def register_middleware(type, sym, cls)
77
+ cls = DeskApi.const_get(type.capitalize).const_get(cls)
78
+ if Faraday.respond_to?(:register_middleware)
79
+ Faraday.register_middleware type, sym => cls
80
+ else
81
+ Faraday.const_get(type.capitalize).register_middleware sym => cls
82
+ end
83
+ end
70
84
 
71
- builder.adapter Faraday.default_adapter
85
+ # Registers the middleware when the module is included.
86
+ def included(_base)
87
+ register_middleware :request, :desk_encode_json, :EncodeJson
88
+ register_middleware :request, :desk_oauth, :OAuth
89
+ register_middleware :request, :desk_retry, :Retry
90
+ register_middleware :response, :desk_parse_dates, :ParseDates
91
+ register_middleware :response, :desk_parse_json, :ParseJson
92
+ register_middleware :response, :desk_raise_error, :RaiseError
93
+ register_middleware :response, :desk_follow_redirects, :FollowRedirects
94
+ end
72
95
  end
73
- end
74
96
 
75
- def configure
76
- yield self
77
- validate_credentials!
78
- validate_endpoint!
79
- self
80
- end
97
+ # Builds the endpoint using the subdomain if the endpoint isn't set
98
+ #
99
+ # @return [String]
100
+ def endpoint
101
+ @endpoint ||= "https://#{@subdomain}.desk.com"
102
+ end
81
103
 
82
- def reset!
83
- DeskApi::Configuration.keys.each do |key|
84
- send("#{key}=", DeskApi::Default.options[key])
104
+ # Returns the middleware proc to be used by Faraday
105
+ #
106
+ # @return [Proc]
107
+ def middleware
108
+ @middleware ||= proc do |builder|
109
+ builder.request(:desk_encode_json)
110
+ builder.request(*authorize_request)
111
+ builder.request(:desk_retry)
112
+
113
+ builder.response(:desk_parse_dates)
114
+ builder.response(:desk_follow_redirects)
115
+ builder.response(:desk_raise_error, DeskApi::Error::ClientError)
116
+ builder.response(:desk_raise_error, DeskApi::Error::ServerError)
117
+ builder.response(:desk_parse_json)
118
+
119
+ builder.adapter(Faraday.default_adapter)
120
+ end
85
121
  end
86
- self
87
- end
88
- alias setup reset!
89
122
 
90
- def credentials?
91
- oauth.values.all? || basic_auth.values.all?
92
- end
123
+ # Allows to configure the client by yielding self.
124
+ #
125
+ # @yield [DeskApi::Client]
126
+ # @return [DeskApi::Client]
127
+ def configure
128
+ yield self
129
+ validate_credentials!
130
+ validate_endpoint!
131
+ self
132
+ end
93
133
 
94
- private
95
- # @return [Hash]
96
- def options
97
- Hash[DeskApi::Configuration.keys.map{|key| [key, instance_variable_get(:"@#{key}")]}]
98
- end
134
+ # Resets the client to the default settings.
135
+ #
136
+ # @return [DeskApi::Client]
137
+ def reset!
138
+ DeskApi::Configuration.keys.each do |key|
139
+ send("#{key}=", DeskApi::Default.options[key])
140
+ end
141
+ self
142
+ end
143
+ alias_method :setup, :reset!
144
+
145
+ # Returns true if either all oauth values or all basic auth
146
+ # values are set.
147
+ #
148
+ # @return [Boolean]
149
+ def credentials?
150
+ oauth.values.all? || basic_auth.values.all?
151
+ end
99
152
 
100
- def oauth
101
- {
102
- consumer_key: @consumer_key,
103
- consumer_secret: @consumer_secret,
104
- token: @token,
105
- token_secret: @token_secret
106
- }
107
- end
153
+ private
108
154
 
109
- def basic_auth
110
- {
111
- username: @username,
112
- password: @password
113
- }
114
- end
155
+ # Returns a hash of current configuration options.
156
+ #
157
+ # @return [Hash]
158
+ def options
159
+ Hash[
160
+ DeskApi::Configuration.keys.map do |key|
161
+ [key, instance_variable_get(:"@#{key}")]
162
+ end
163
+ ]
164
+ end
115
165
 
116
- def validate_credentials!
117
- unless credentials?
118
- raise(DeskApi::Error::ConfigurationError, "Invalid credentials: Either username/password or OAuth credentials must be specified.")
166
+ # Returns the oauth configuration options.
167
+ #
168
+ # @return [Hash]
169
+ def oauth
170
+ {
171
+ consumer_key: @consumer_key,
172
+ consumer_secret: @consumer_secret,
173
+ token: @token,
174
+ token_secret: @token_secret
175
+ }
119
176
  end
120
177
 
121
- if oauth.values.all?
122
- oauth.each do |credential, value|
123
- next if value.nil?
178
+ # Returns the basic auth configuration options.
179
+ #
180
+ # @return [Hash]
181
+ def basic_auth
182
+ {
183
+ username: @username,
184
+ password: @password
185
+ }
186
+ end
124
187
 
125
- unless value.is_a?(String) || value.is_a?(Symbol)
126
- raise(DeskApi::Error::ConfigurationError, "Invalid #{credential} specified: #{value} must be a string or symbol.")
127
- end
188
+ # Returns an array to authorize a request in the
189
+ # middleware proc.
190
+ #
191
+ # @return [Array]
192
+ def authorize_request
193
+ if basic_auth.values.all?
194
+ [:basic_auth, @username, @password]
195
+ else
196
+ [:desk_oauth, oauth]
128
197
  end
129
198
  end
130
199
 
131
- if basic_auth.values.all?
132
- basic_auth.each do |credential, value|
133
- next if value.nil?
200
+ # Raises an error if credentials are not set or of
201
+ # the wrong type.
202
+ #
203
+ # @raise [DeskApi::Error::ConfigurationError]
204
+ def validate_credentials!
205
+ fail(
206
+ DeskApi::Error::ConfigurationError, 'Invalid credentials: ' \
207
+ 'Either username/password or OAuth credentials must be specified.'
208
+ ) unless credentials?
209
+
210
+ validate_oauth! if oauth.values.all?
211
+ validate_basic_auth! if basic_auth.values.all?
212
+ end
134
213
 
135
- unless value.is_a?(String) || value.is_a?(Symbol)
136
- raise(DeskApi::Error::ConfigurationError, "Invalid #{credential} specified: #{value} must be a string or symbol.")
214
+ # Raises an error if credentials are of the wrong type.
215
+ #
216
+ # @raise [DeskApi::Error::ConfigurationError]
217
+ %w(oauth basic_auth).each do |type|
218
+ define_method(:"validate_#{type}!") do
219
+ send(type.to_sym).each_pair do |credential, value|
220
+ next if value.nil?
221
+
222
+ fail(
223
+ DeskApi::Error::ConfigurationError, "Invalid #{credential} " \
224
+ "specified: must be a string or symbol."
225
+ ) unless value.is_a?(String) || value.is_a?(Symbol)
137
226
  end
138
227
  end
139
228
  end
140
- end
141
229
 
142
- def validate_endpoint!
143
- unless endpoint =~ /^#{URI::regexp}$/
144
- raise(DeskApi::Error::ConfigurationError, "Invalid endpoint specified: `#{endpoint}` must be a valid url.")
230
+ # Raises an error if the endpoint is not a valid URL.
231
+ #
232
+ # @raises [DeskApi::Error::ConfigurationError]
233
+ def validate_endpoint!
234
+ fail(
235
+ DeskApi::Error::ConfigurationError,
236
+ "Invalid endpoint specified: `#{endpoint}` must be a valid url."
237
+ ) unless endpoint =~ /^#{URI.regexp}$/
145
238
  end
146
239
  end
147
240
  end
@@ -1,63 +1,120 @@
1
- module DeskApi::Default
2
- CONNECTION_OPTIONS = {
3
- headers: {
4
- accept: 'application/json',
5
- user_agent: "desk.com Ruby Gem v#{DeskApi::VERSION}"
6
- },
7
- request: {
8
- open_timeout: 5,
9
- timeout: 10
10
- }
11
- } unless defined? DeskApi::Default::CONNECTION_OPTIONS
12
-
13
- class << self
14
- # @return [Hash]
15
- def options
16
- Hash[DeskApi::Configuration.keys.map{|key| [key, send(key)]}]
17
- end
1
+ # Copyright (c) 2013-2014, Salesforce.com, Inc.
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification,
5
+ # are permitted provided that the following conditions are met:
6
+ #
7
+ # * Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # * Neither the name of Salesforce.com nor the names of its contributors may be
15
+ # used to endorse or promote products derived from this software without
16
+ # specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22
+ # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25
+ # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
28
 
19
- # @return [String]
20
- def username
21
- ENV['DESK_USERNAME']
22
- end
29
+ module DeskApi
30
+ # {DeskApi::Default} contains the default configuration for each
31
+ # {DeskApi::Client}.
32
+ #
33
+ # @author Thomas Stachl <tstachl@salesforce.com>
34
+ # @copyright Copyright (c) 2013-2014 Salesforce.com
35
+ # @license BSD 3-Clause License
36
+ module Default
37
+ CONNECTION_OPTIONS = {
38
+ headers: {
39
+ accept: 'application/json',
40
+ user_agent: "desk.com Ruby Gem v#{DeskApi::VERSION}"
41
+ },
42
+ request: {
43
+ open_timeout: 5,
44
+ timeout: 10
45
+ }
46
+ } unless defined? DeskApi::Default::CONNECTION_OPTIONS
23
47
 
24
- # @return [String]
25
- def password
26
- ENV['DESK_PASSWORD']
27
- end
48
+ class << self
49
+ # A hash of all the options
50
+ #
51
+ # @return [Hash]
52
+ def options
53
+ Hash[DeskApi::Configuration.keys.map { |key| [key, send(key)] }]
54
+ end
28
55
 
29
- # @return [String]
30
- def consumer_key
31
- ENV['DESK_CONSUMER_KEY']
32
- end
56
+ # The username if environmental variable is set
57
+ #
58
+ # @return [String]
59
+ def username
60
+ ENV['DESK_USERNAME']
61
+ end
33
62
 
34
- # @return [String]
35
- def consumer_secret
36
- ENV['DESK_CONSUMER_SECRET']
37
- end
63
+ # The password if environmental variable is set
64
+ #
65
+ # @return [String]
66
+ def password
67
+ ENV['DESK_PASSWORD']
68
+ end
38
69
 
39
- # @return [String]
40
- def token
41
- ENV['DESK_TOKEN']
42
- end
70
+ # The consumer key if environmental variable is set
71
+ #
72
+ # @return [String]
73
+ def consumer_key
74
+ ENV['DESK_CONSUMER_KEY']
75
+ end
43
76
 
44
- # @return [String]
45
- def token_secret
46
- ENV['DESK_TOKEN_SECRET']
47
- end
77
+ # The consumer secret if environmental variable is set
78
+ #
79
+ # @return [String]
80
+ def consumer_secret
81
+ ENV['DESK_CONSUMER_SECRET']
82
+ end
48
83
 
49
- # @return [String]
50
- def subdomain
51
- ENV['DESK_SUBDOMAIN']
52
- end
84
+ # The access token if environmental variable is set
85
+ #
86
+ # @return [String]
87
+ def token
88
+ ENV['DESK_TOKEN']
89
+ end
53
90
 
54
- # @return [String]
55
- def endpoint
56
- ENV['DESK_ENDPOINT']
57
- end
91
+ # The access token secret if environmental variable is set
92
+ #
93
+ # @return [String]
94
+ def token_secret
95
+ ENV['DESK_TOKEN_SECRET']
96
+ end
97
+
98
+ # The subdomain if environmental variable is set
99
+ #
100
+ # @return [String]
101
+ def subdomain
102
+ ENV['DESK_SUBDOMAIN']
103
+ end
104
+
105
+ # The endpoint if environmental variable is set
106
+ #
107
+ # @return [String]
108
+ def endpoint
109
+ ENV['DESK_ENDPOINT']
110
+ end
58
111
 
59
- def connection_options
60
- CONNECTION_OPTIONS
112
+ # The connection options hash
113
+ #
114
+ # @return [Hash]
115
+ def connection_options
116
+ CONNECTION_OPTIONS
117
+ end
61
118
  end
62
119
  end
63
- end
120
+ end