paid 0.1.0 → 1.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -1
  3. data/.travis.yml +16 -0
  4. data/History.txt +4 -0
  5. data/README.md +58 -0
  6. data/Rakefile +9 -29
  7. data/VERSION +1 -0
  8. data/bin/paid-console +7 -0
  9. data/gemfiles/default-with-activesupport.gemfile +10 -0
  10. data/gemfiles/json.gemfile +12 -0
  11. data/gemfiles/yajl.gemfile +12 -0
  12. data/lib/paid.rb +129 -177
  13. data/lib/paid/account.rb +14 -1
  14. data/lib/paid/api_class.rb +336 -0
  15. data/lib/paid/api_list.rb +47 -0
  16. data/lib/paid/api_resource.rb +8 -25
  17. data/lib/paid/api_singleton.rb +5 -0
  18. data/lib/paid/customer.rb +36 -21
  19. data/lib/paid/errors/api_error.rb +6 -0
  20. data/lib/paid/event.rb +22 -1
  21. data/lib/paid/invoice.rb +16 -21
  22. data/lib/paid/plan.rb +18 -2
  23. data/lib/paid/subscription.rb +17 -11
  24. data/lib/paid/transaction.rb +19 -12
  25. data/lib/paid/util.rb +53 -106
  26. data/lib/paid/version.rb +1 -1
  27. data/paid.gemspec +10 -11
  28. data/tasks/api_test.rb +187 -0
  29. data/test/mock_resource.rb +69 -0
  30. data/test/paid/account_test.rb +41 -4
  31. data/test/paid/api_class_test.rb +412 -0
  32. data/test/paid/api_list_test.rb +17 -0
  33. data/test/paid/api_resource_test.rb +13 -343
  34. data/test/paid/api_singleton_test.rb +12 -0
  35. data/test/paid/authentication_test.rb +50 -0
  36. data/test/paid/customer_test.rb +189 -29
  37. data/test/paid/event_test.rb +74 -0
  38. data/test/paid/invoice_test.rb +101 -20
  39. data/test/paid/plan_test.rb +84 -8
  40. data/test/paid/status_codes_test.rb +63 -0
  41. data/test/paid/subscription_test.rb +100 -20
  42. data/test/paid/transaction_test.rb +110 -37
  43. data/test/paid/util_test.rb +15 -24
  44. data/test/test_data.rb +144 -93
  45. data/test/test_helper.rb +6 -4
  46. metadata +32 -26
  47. data/Gemfile.lock +0 -54
  48. data/README.rdoc +0 -35
  49. data/lib/data/ca-certificates.crt +0 -0
  50. data/lib/paid/alias.rb +0 -16
  51. data/lib/paid/api_operations/create.rb +0 -17
  52. data/lib/paid/api_operations/delete.rb +0 -11
  53. data/lib/paid/api_operations/list.rb +0 -17
  54. data/lib/paid/api_operations/update.rb +0 -57
  55. data/lib/paid/certificate_blacklist.rb +0 -55
  56. data/lib/paid/list_object.rb +0 -37
  57. data/lib/paid/paid_object.rb +0 -187
  58. data/lib/paid/singleton_api_resource.rb +0 -20
  59. data/lib/tasks/paid_tasks.rake +0 -4
  60. data/test/paid/alias_test.rb +0 -22
  61. data/test/paid/certificate_blacklist_test.rb +0 -18
  62. data/test/paid/list_object_test.rb +0 -16
  63. data/test/paid/paid_object_test.rb +0 -27
  64. data/test/paid/properties_test.rb +0 -103
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c131f42824035c881ba3eaf3896d2a8e79aa9a26
4
- data.tar.gz: c2b902c2b3d7e0fba75c67b71ec3cff06db9fc98
3
+ metadata.gz: 19719c911ec26dca4ded160c1bd21384fd783939
4
+ data.tar.gz: 29fe6d251b7c798dcc9d962a9b3cd1f7b9366d0d
5
5
  SHA512:
6
- metadata.gz: 97115b5ea5004e528b213f9fc9800d5adfebe63d6ff7c0ed95f98f06a04d4acc0523067a285707521a6ce19ef365ec38768aed459cfa6da6e37afe61a72dd339
7
- data.tar.gz: b1b15a66a2e5c093635e35d790bc9c801ad03143f595e1d86c512a26f7e88885a6adbeb69731fd1ca5ee5fa630c90f013549ec1d2b3e8398a1cf1f1bed29258c
6
+ metadata.gz: 2cb3e08c5d99736ae837e89231465b8a90f24a2558ef0ebb897bf1cc8d6483a1ad99fcc9a8e6228fd30092c5266d6fe52e817308d2af456354515fe677df89a3
7
+ data.tar.gz: b05a5e6fe08b76c77eae783f9d687bc44fd2c0806c38fcaf5add389ef59ec5d3ff0d989bbf03f84011d9ac6b3cefc6de8c0ccd01713edbff624e4127725fb317
data/.gitignore CHANGED
@@ -1 +1,5 @@
1
- pkg
1
+ pkg
2
+ Gemfile.lock
3
+ *.gem
4
+ test.rb
5
+ .ruby-version
data/.travis.yml ADDED
@@ -0,0 +1,16 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.8.7
5
+ - 1.9.2
6
+ - 1.9.3
7
+ - 2.0.0
8
+ - 2.1
9
+ - 2.2
10
+
11
+ gemfile:
12
+ - gemfiles/default-with-activesupport.gemfile
13
+ - gemfiles/json.gemfile
14
+ - gemfiles/yajl.gemfile
15
+
16
+ sudo: false
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 1.0 2015-03-04
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Paid Ruby bindings ![Travis CI Status](https://travis-ci.org/paidapi/paid-ruby.svg?branch=master)
2
+
3
+
4
+ ## Installation
5
+
6
+ You don't need this source code unless you want to modify the gem. If
7
+ you just want to use the Paid Ruby bindings, you should run:
8
+
9
+ ```bash
10
+ gem install paid
11
+ ```
12
+
13
+ If you want to build the gem from source:
14
+
15
+ ```bash
16
+ gem build paid.gemspec
17
+ ```
18
+
19
+
20
+ ## Requirements
21
+
22
+ * Ruby 1.8.7 or above. (Ruby 1.8.6 may work if you load
23
+ ActiveSupport.) For Ruby versions before 1.9.2, you'll need to add this to your Gemfile:
24
+
25
+ ```ruby
26
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.2')
27
+ gem 'rest-client', '~> 1.6.8'
28
+ end
29
+ ```
30
+
31
+ * rest-client, json
32
+
33
+
34
+ ## Bundler
35
+
36
+ If you are installing via bundler, you should be sure to use the https
37
+ rubygems source in your Gemfile, as any gems fetched over http could potentially be compromised.
38
+
39
+ ```ruby
40
+ source 'https://rubygems.org'
41
+
42
+ gem 'rails'
43
+ gem 'paid'
44
+ ```
45
+
46
+
47
+ ## Development
48
+
49
+ Test cases can be run with: `bundle exec rake test`
50
+
51
+
52
+ ## Test Rake Task
53
+
54
+ To hit the API with some test calls run:
55
+
56
+ ```bash
57
+ bundle exec rake test_api["sk_test_api_key"]
58
+ ```
data/Rakefile CHANGED
@@ -1,34 +1,14 @@
1
- begin
2
- require 'bundler/setup'
3
- rescue LoadError
4
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
- end
1
+ require 'rake/testtask'
2
+ require './tasks/api_test.rb'
6
3
 
7
- require 'rdoc/task'
4
+ task :default => [:test]
8
5
 
9
- RDoc::Task.new(:rdoc) do |rdoc|
10
- rdoc.rdoc_dir = 'rdoc'
11
- rdoc.title = 'Paid'
12
- rdoc.options << '--line-numbers'
13
- rdoc.rdoc_files.include('README.rdoc')
14
- rdoc.rdoc_files.include('lib/**/*.rb')
6
+ Rake::TestTask.new do |t|
7
+ t.pattern = './test/**/*_test.rb'
15
8
  end
16
9
 
17
-
18
-
19
-
20
-
21
-
22
- Bundler::GemHelper.install_tasks
23
-
24
- require 'rake/testtask'
25
-
26
- Rake::TestTask.new(:test) do |t|
27
- t.libs << 'lib'
28
- t.libs << 'test'
29
- t.pattern = 'test/**/*_test.rb'
30
- t.verbose = false
10
+ task :test_api, [:api_key] do |t, args|
11
+ api_key = args[:api_key]
12
+ api_test = APITest.new(api_key)
13
+ api_test.run
31
14
  end
32
-
33
-
34
- task default: :test
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/bin/paid-console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
3
+
4
+ libs = " -r irb/completion"
5
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/paid'}"
6
+ puts "Loading paid gem"
7
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+ gemspec :path => File.join(File.dirname(__FILE__), "..")
3
+
4
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.3')
5
+ gem 'i18n', '< 0.7'
6
+ gem 'rest-client', '~> 1.6.8'
7
+ gem 'activesupport', '~> 3.2'
8
+ else
9
+ gem 'activesupport'
10
+ end
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+ gemspec :path => File.join(File.dirname(__FILE__), "..")
3
+
4
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.3')
5
+ gem 'i18n', '< 0.7'
6
+ gem 'rest-client', '~> 1.6.8'
7
+ gem 'activesupport', '~> 3.2'
8
+ else
9
+ gem 'activesupport'
10
+ end
11
+
12
+ gem 'json'
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+ gemspec :path => File.join(File.dirname(__FILE__), "..")
3
+
4
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.3')
5
+ gem 'i18n', '< 0.7'
6
+ gem 'rest-client', '~> 1.6.8'
7
+ gem 'activesupport', '~> 3.2'
8
+ else
9
+ gem 'activesupport'
10
+ end
11
+
12
+ gem 'yajl-ruby'
data/lib/paid.rb CHANGED
@@ -1,35 +1,30 @@
1
1
  # Paid Ruby bindings
2
- # API spec at https://docs.paidapi.com
2
+ # API spec at https://paid.com/docs/api
3
3
  require 'cgi'
4
4
  require 'set'
5
5
  require 'openssl'
6
6
  require 'rest_client'
7
7
  require 'json'
8
+ require 'base64'
8
9
 
9
10
  # Version
10
11
  require 'paid/version'
11
12
 
12
- # API operations
13
- require 'paid/api_operations/create'
14
- require 'paid/api_operations/update'
15
- require 'paid/api_operations/delete'
16
- require 'paid/api_operations/list'
17
-
18
13
  # Resources
19
- require 'paid/util'
20
- require 'paid/paid_object'
14
+ require 'paid/api_class'
21
15
  require 'paid/api_resource'
22
- require 'paid/singleton_api_resource'
23
- require 'paid/list_object'
24
- require 'paid/account'
25
- require 'paid/customer'
26
- require 'paid/certificate_blacklist'
27
- require 'paid/invoice'
16
+ require 'paid/api_singleton'
17
+ require 'paid/api_list'
18
+ require 'paid/util'
19
+
20
+ # Requires for classes
28
21
  require 'paid/transaction'
22
+ require 'paid/invoice'
29
23
  require 'paid/event'
30
- require 'paid/alias'
24
+ require 'paid/customer'
31
25
  require 'paid/plan'
32
26
  require 'paid/subscription'
27
+ require 'paid/account'
33
28
 
34
29
  # Errors
35
30
  require 'paid/errors/paid_error'
@@ -39,114 +34,93 @@ require 'paid/errors/invalid_request_error'
39
34
  require 'paid/errors/authentication_error'
40
35
 
41
36
  module Paid
42
- DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/data/ca-certificates.crt'
43
- @api_base = 'https://api.paidapi.com'
44
-
45
- @ssl_bundle_path = DEFAULT_CA_BUNDLE_PATH
46
- @verify_ssl_certs = false
47
- @CERTIFICATE_VERIFIED = false
48
-
37
+ @api_base = "https://api.paidapi.com"
38
+ @api_key = nil
49
39
 
50
40
  class << self
51
- attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version
41
+ attr_accessor :api_key, :api_base, :api_test
52
42
  end
53
43
 
54
- def self.api_url(url='', api_base_url=nil)
55
- (api_base_url || @api_base) + url
44
+ def self.api_url(path='')
45
+ "#{@api_base}#{path}"
56
46
  end
57
47
 
58
- def self.request(method, url, api_key, params={}, headers={}, api_base_url=nil)
59
- api_base_url = api_base_url || @api_base
60
-
61
-
62
- unless api_key ||= @api_key
63
- raise AuthenticationError.new('No API key provided. ' +
64
- 'Set your API key using "Paid.api_key = <API-KEY>". ' +
65
- 'You can generate API keys from the Paid web interface. ' +
66
- 'See https://paidapi.com/api for details, or email hello@paidapi.com ' +
67
- 'if you have any questions.')
68
- end
69
-
70
- if api_key =~ /\s/
71
- raise AuthenticationError.new('Your API key is invalid, as it contains ' +
72
- 'whitespace. (HINT: You can double-check your API key from the ' +
73
- 'Paid web interface. See https://paidapi.com/api for details, or ' +
74
- 'email hello@paidapi.com if you have any questions.)')
75
- end
48
+ def self.request(method, path, params={}, headers={})
49
+ verify_api_key(api_key)
76
50
 
51
+ url = api_url(path)
77
52
 
78
53
  request_opts = { :verify_ssl => false }
79
54
 
80
- if ssl_preflight_passed?
81
- request_opts.update(:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
82
- :ssl_ca_file => @ssl_bundle_path)
83
- end
84
-
85
- if @verify_ssl_certs and !@CERTIFICATE_VERIFIED
86
- @CERTIFICATE_VERIFIED = CertificateBlacklist.check_ssl_cert(api_base_url, @ssl_bundle_path)
87
- end
88
-
89
- params = Util.objects_to_ids(params)
90
- url = api_url(url, api_base_url)
91
-
92
- case method.to_s.downcase.to_sym
93
- when :get, :head, :delete
94
- # Make params into GET parameters
95
- url += "#{URI.parse(url).query ? '&' : '?'}#{uri_encode(params)}" if params && params.any?
96
- payload = nil
97
- else
98
- if headers[:content_type] && headers[:content_type] == "multipart/form-data"
99
- payload = params
100
- else
101
- payload = uri_encode(params)
55
+ if [:get, :head, :delete].include?(method.to_s.downcase.to_sym)
56
+ unless params.empty?
57
+ url += URI.parse(url).query ? '&' : '?' + Util.query_string(params)
102
58
  end
59
+ params = nil
103
60
  end
104
61
 
105
- request_opts.update(:headers => request_headers(api_key).update(headers),
106
- :method => method, :open_timeout => 30,
107
- :payload => payload, :url => url, :timeout => 80)
62
+ headers = default_headers.update(basic_auth_headers(api_key)).update(headers)
63
+ request_opts.update(:headers => headers,
64
+ :method => method,
65
+ :open_timeout => 30,
66
+ :payload => params,
67
+ :url => url,
68
+ :timeout => 60)
69
+
108
70
  begin
109
71
  response = execute_request(request_opts)
110
- rescue SocketError => e
111
- handle_restclient_error(e, api_base_url)
112
- rescue NoMethodError => e
113
- # Work around RestClient bug
114
- if e.message =~ /\WRequestFailed\W/
115
- e = APIConnectionError.new('Unexpected HTTP response code')
116
- handle_restclient_error(e, api_base_url)
117
- else
118
- raise
119
- end
120
- rescue RestClient::ExceptionWithResponse => e
121
- if rcode = e.http_code and rbody = e.http_body
122
- handle_api_error(rcode, rbody)
123
- else
124
- handle_restclient_error(e, api_base_url)
125
- end
126
- rescue RestClient::Exception, Errno::ECONNREFUSED => e
127
- handle_restclient_error(e, api_base_url)
128
72
  rescue Exception => e
73
+ handle_request_error(e, url)
129
74
  end
130
75
 
76
+ parse(response)
77
+ end
131
78
 
132
- [parse(response), api_key]
79
+ # Mostly here for stubbing out during tests.
80
+ def self.execute_request(opts)
81
+ RestClient::Request.execute(opts)
133
82
  end
134
83
 
135
- private
84
+ def self.parse(response)
85
+ begin
86
+ json = JSON.parse(response.body)
87
+ rescue JSON::ParserError
88
+ raise APIError.generic(response.code, response.body)
89
+ end
136
90
 
137
- def self.ssl_preflight_passed?
138
- if !verify_ssl_certs && !@no_verify
139
- "Execute 'Paid.verify_ssl_certs = true' to enable verification."
91
+ # TODO(jonclahoun): Remove this when Paid's API returns the correct status code.
92
+ json = Util.symbolize_keys(json)
93
+ if json.has_key?(:error)
94
+ raise PaidError.new(json[:error][:message], response.code, response.body, json)
95
+ end
96
+ json
97
+ end
140
98
 
141
- @no_verify = true
99
+ def self.default_headers
100
+ headers = {
101
+ :user_agent => "Paid/::API_VERSION:: RubyBindings/#{Paid::VERSION}",
102
+ :content_type => 'application/x-www-form-urlencoded'
103
+ }
142
104
 
143
- elsif !Util.file_readable(@ssl_bundle_path) && !@no_bundle
144
- "because #{@ssl_bundle_path} isn't readable"
105
+ begin
106
+ headers.update(:x_paid_client_user_agent => JSON.generate(user_agent))
107
+ rescue => e
108
+ headers.update(:x_paid_client_raw_user_agent => user_agent.inspect,
109
+ :error => "#{e} (#{e.class})")
110
+ end
111
+ headers
112
+ end
145
113
 
146
- @no_bundle = true
114
+ def self.basic_auth_headers(api_key=@api_key)
115
+ api_key ||= @api_key
116
+ unless api_key
117
+ raise ArgumentError.new('No API key provided. Set your API key using "Paid.api_key = <API-KEY>".')
147
118
  end
148
119
 
149
- !(@no_verify || @no_bundle)
120
+ base_64_key = Base64.encode64("#{api_key}:")
121
+ {
122
+ "Authorization" => "Basic #{base_64_key}",
123
+ }
150
124
  end
151
125
 
152
126
  def self.user_agent
@@ -161,7 +135,6 @@ module Paid
161
135
  :publisher => 'paid',
162
136
  :uname => @uname
163
137
  }
164
-
165
138
  end
166
139
 
167
140
  def self.get_uname
@@ -170,95 +143,49 @@ module Paid
170
143
  "uname lookup failed"
171
144
  end
172
145
 
173
- def self.uri_encode(params)
174
- Util.flatten_params(params).
175
- map { |k,v| "#{k}=#{Util.url_encode(v)}" }.join('&')
176
- end
177
-
178
- def self.request_headers(api_key)
179
- headers = {
180
- :user_agent => "Paid/v0 RubyBindings/#{Paid::VERSION}",
181
- :authorization => "Bearer #{api_key}",
182
- :content_type => 'application/x-www-form-urlencoded'
183
- }
184
-
185
- headers[:paid_version] = api_version if api_version
186
-
187
- begin
188
- headers.update(:x_paid_client_user_agent => JSON.generate(user_agent))
189
- rescue => e
190
- headers.update(:x_paid_client_raw_user_agent => user_agent.inspect,
191
- :error => "#{e} (#{e.class})")
146
+ def self.verify_api_key(api_key)
147
+ unless api_key
148
+ raise AuthenticationError.new('No API key provided. ' +
149
+ 'Set your API key using "Paid.api_key = <API-KEY>". ' +
150
+ 'You can generate API keys from the Paid web interface. ' +
151
+ 'See http://docs.paidapi.com/#authentication for details, or email hello@paidapi.com ' +
152
+ 'if you have any questions.')
192
153
  end
193
- end
194
-
195
- def self.execute_request(opts)
196
- RestClient::Request.execute(opts)
197
- end
198
154
 
199
- def self.parse(response)
200
- begin
201
- # Would use :symbolize_names => true, but apparently there is
202
- # some library out there that makes symbolize_names not work.
203
- response = JSON.parse(response.body)
204
- rescue JSON::ParserError
205
- raise general_api_error(response.code, response.body)
155
+ if api_key =~ /\s/
156
+ raise AuthenticationError.new('Your API key is invalid, as it contains ' +
157
+ 'whitespace. (HINT: You can double-check your API key from the ' +
158
+ 'Paid web interface. See http://docs.paidapi.com/#authentication for details, or ' +
159
+ 'email hello@paidapi.com if you have any questions.)')
206
160
  end
207
-
208
- Util.symbolize_names(response)
209
- end
210
-
211
- def self.general_api_error(rcode, rbody)
212
- APIError.new("Invalid response object from API: #{rbody.inspect} " +
213
- "(HTTP response code was #{rcode})", rcode, rbody)
214
161
  end
215
162
 
216
- def self.handle_api_error(rcode, rbody)
217
- begin
218
- error_obj = JSON.parse(rbody)
219
- error_obj = Util.symbolize_names(error_obj)
220
- error = error_obj[:error] or raise PaidError.new # escape from parsing
221
-
222
- rescue JSON::ParserError, PaidError
223
- raise general_api_error(rcode, rbody)
163
+ def self.handle_request_error(error, url)
164
+ # First we see if this is an error with a response, and if it is
165
+ # we check to see if there is an http code and body to work with.
166
+ if error.is_a?(RestClient::ExceptionWithResponse)
167
+ if error.http_code && error.http_body
168
+ handle_api_error(error.http_code, error.http_body)
169
+ end
224
170
  end
225
171
 
226
- case rcode
227
- when 400, 404
228
- raise invalid_request_error error, rcode, rbody, error_obj
229
- when 401
230
- raise authentication_error error, rcode, rbody, error_obj
231
- else
232
- raise api_error error, rcode, rbody, error_obj
233
- end
172
+ # If we got here then the error hasn't been handled yet.
173
+ # Handle it as a connection error.
174
+ handle_connection_error(error, url)
234
175
 
176
+ # Finally if we get here we don't know what type of error it is, so just raise it.
177
+ raise error
235
178
  end
236
179
 
237
- def self.invalid_request_error(error, rcode, rbody, error_obj)
238
- InvalidRequestError.new(error[:message], error[:param], rcode,
239
- rbody, error_obj)
240
- end
180
+ def self.handle_connection_error(error, url)
181
+ message = "An error occurred while connecting to Paid at #{url}."
241
182
 
242
- def self.authentication_error(error, rcode, rbody, error_obj)
243
- AuthenticationError.new(error[:message], rcode, rbody, error_obj)
244
- end
245
-
246
- def self.api_error(error, rcode, rbody, error_obj)
247
- APIError.new(error[:message], rcode, rbody, error_obj)
248
- end
249
-
250
- def self.handle_restclient_error(e, api_base_url=nil)
251
- api_base_url = @api_base unless api_base_url
252
- connection_message = "Please check your internet connection and try again. " \
253
- "If this problem persists, you should check Paid's service status at " \
254
- "https://twitter.com/paidstatus, or let us know at hello@paidapi.com."
255
-
256
- case e
183
+ case error
257
184
  when RestClient::RequestTimeout
258
- message = "Could not connect to Paid (#{api_base_url}). #{connection_message}"
185
+ message += connection_message
259
186
 
260
187
  when RestClient::ServerBrokeConnection
261
- message = "The connection to the server (#{api_base_url}) broke before the " \
188
+ message = "The connection to the server at (#{url}) broke before the " \
262
189
  "request completed. #{connection_message}"
263
190
 
264
191
  when RestClient::SSLCertificateNotVerified
@@ -268,16 +195,41 @@ module Paid
268
195
  "If this problem persists, let us know at hello@paidapi.com."
269
196
 
270
197
  when SocketError
271
- message = "Unexpected error communicating when trying to connect to Paid. " \
198
+ message = "Unexpected error when trying to connect to Paid. " \
272
199
  "You may be seeing this message because your DNS is not working. " \
273
- "To check, try running 'host paidapi.com' from the command line."
200
+ "To check, try running 'host api.paidapi.com' from the command line."
274
201
 
275
202
  else
276
203
  message = "Unexpected error communicating with Paid. " \
277
- "If this problem persists, let us know at hello@paidapi.com."
204
+ "If this problem persists, let us know at hello@paidapi.com. #{connection_message}"
205
+ end
278
206
 
207
+ raise APIConnectionError.new(message + "\n\n(Network error: #{error.message}")
208
+ end
209
+
210
+ def self.connection_message
211
+ "Please check your internet connection and try again. " \
212
+ "If this problem persists, you should check Paid's service status at " \
213
+ "https://twitter.com/paidstatus, or let us know at hello@paidapi.com."
214
+ end
215
+
216
+ def self.handle_api_error(rcode, rbody)
217
+ begin
218
+ error_obj = JSON.parse(rbody)
219
+ rescue JSON::ParserError
220
+ raise APIError.generic(rcode, rbody)
279
221
  end
222
+ error_obj = Util.symbolize_keys(error_obj)
223
+ raise APIError.generic(rcode, rbody) unless error = error_obj[:error]
280
224
 
281
- raise APIConnectionError.new(message + "\n\n(Network error: #{e.message})")
225
+ case rcode
226
+ when 400, 404
227
+ raise InvalidRequestError.new(error[:message], error[:param], rcode, rbody, error_obj)
228
+ when 401
229
+ raise AuthenticationError.new(error[:message], rcode, rbody, error_obj)
230
+ else
231
+ raise APIError.new(error[:message], rcode, rbody, error_obj)
232
+ end
282
233
  end
234
+
283
235
  end