desk_api 0.6.0 → 0.6.1

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.
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