paddle 2.2.1 → 2.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6224fc2a3ec9423990985241a118780185a090617407f95e97bb542120eb9323
4
- data.tar.gz: 03403341d8dce73c881ed3fc2c722cf738b625803c6352dd2cca15e5d4cd65a7
3
+ metadata.gz: fd93d2c8220b972ffa99dc9134c9ae6a1dd4da4051d63d363f825f4130be5965
4
+ data.tar.gz: 4e6f0566db66650772cef15c976d229221cf3292b8a60f044ac22cfe91f81d70
5
5
  SHA512:
6
- metadata.gz: 6453da01350a80adf7f8723817b7d45edfac636d5ae72ebeb92b281ad93d85d59866631eb60a17c3a8225f5a8f51780b857e1aeab940c0264daaa53446a70637
7
- data.tar.gz: 716ef3061039df26a5cfc0dd0f8931cb1e9edcf964947047acf37ed8b95cc63a3cc36595288f6aaccc45ee2b1e3f8fe0b74ae39969123f2c99eeeeea9da41381
6
+ metadata.gz: 51904dcd27cdc1272ffffe94397ab53756a07cf0de48071d8e4b4830efd51533965296dd7f0b74667e6a0be0f9f6dd3ec2fbba6dda6f2b512983ab01be0e4096
7
+ data.tar.gz: aedd0b4538ed33115788157c00e18b06c83da69ac0491fa1f62f69ecf5c77cebc9e27c9f8e9aa51bfd23bf13a94f67a97f8657bd7a29d3b42bc4a2c9bb41d311
data/.rubocop.yml CHANGED
@@ -6,3 +6,6 @@ inherit_gem: { rubocop-rails-omakase: rubocop.yml }
6
6
  # # Use `[a, [b, c]]` not `[ a, [ b, c ] ]`
7
7
  # Layout/SpaceInsideArrayLiteralBrackets:
8
8
  # Enabled: false
9
+
10
+ Rails/RefuteMethods:
11
+ Enabled: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- paddle (2.2.1)
4
+ paddle (2.3.0)
5
5
  faraday (~> 2.0)
6
6
 
7
7
  GEM
@@ -40,9 +40,9 @@ GEM
40
40
  ast (~> 2.4.1)
41
41
  racc
42
42
  racc (1.8.0)
43
- rack (3.1.3)
43
+ rack (3.1.7)
44
44
  rainbow (3.1.1)
45
- rake (13.0.6)
45
+ rake (13.2.1)
46
46
  regexp_parser (2.9.2)
47
47
  rexml (3.3.0)
48
48
  strscan
data/README.md CHANGED
@@ -77,6 +77,14 @@ Paddle::Product.list(per_page: 10, after: "abc123")
77
77
  >
78
78
  > The Paddle API doesn't take `nil` values for optional parameters. If you want to remove a value, you'll need to pass `"null"` instead.
79
79
 
80
+ ### Updating records
81
+
82
+ For API endpoints that support it, you can use the `update` method to update a record, like so:
83
+
84
+ ```ruby
85
+ Paddle::Product.retrieve(id: "pro_abc123").update(name: "My New Name")
86
+ ```
87
+
80
88
  ### Products
81
89
 
82
90
  ```ruby
@@ -167,6 +175,7 @@ Paddle::Customer.list(email: "me@mydomain.com")
167
175
 
168
176
  # Create a customer
169
177
  # https://developer.paddle.com/api-reference/customers/create-customer
178
+ # Returns a Paddle::ConflictError if the email is already used on Paddle
170
179
  Paddle::Customer.create(email: "myemail@mydomain.com", name: "Customer Name")
171
180
 
172
181
  # Retrieve a customer
data/lib/paddle/client.rb CHANGED
@@ -1,66 +1,61 @@
1
+ require "faraday"
2
+
1
3
  module Paddle
2
4
  class Client
3
5
  class << self
4
6
  def connection
5
- @connection ||= Faraday.new(Paddle.config.url) do |conn|
6
- conn.request :authorization, :Bearer, Paddle.config.api_key
7
-
8
- conn.headers = {
9
- "User-Agent" => "paddle/v#{VERSION} (github.com/deanpcmad/paddle)",
10
- "Paddle-Version" => Paddle.config.version.to_s
11
- }
12
-
13
- conn.request :json
14
- conn.response :json
15
- end
7
+ @connection ||= create_connection
16
8
  end
17
9
 
18
-
19
10
  def get_request(url, params: {}, headers: {})
20
- handle_response connection.get(url, params, headers)
11
+ handle_response(connection.get(url, params, headers))
21
12
  end
22
13
 
23
14
  def post_request(url, body: {}, headers: {})
24
- handle_response connection.post(url, body, headers)
15
+ handle_response(connection.post(url, body, headers))
25
16
  end
26
17
 
27
18
  def patch_request(url, body:, headers: {})
28
- handle_response connection.patch(url, body, headers)
19
+ handle_response(connection.patch(url, body, headers))
29
20
  end
30
21
 
31
22
  def delete_request(url, headers: {})
32
- handle_response connection.delete(url, headers)
23
+ handle_response(connection.delete(url, headers))
33
24
  end
34
25
 
35
- def handle_response(response)
36
- case response.status
37
- when 400
38
- raise Error, "Error 400: Your request was malformed. '#{response.body["error"]["code"]}'"
39
- when 401
40
- raise Error, "Error 401: You did not supply valid authentication credentials. '#{response.body["error"]}'"
41
- when 403
42
- raise Error, "Error 403: You are not allowed to perform that action. '#{response.body["error"]["code"]}'"
43
- when 404
44
- raise Error, "Error 404: No results were found for your request. '#{response.body["error"]["code"]}'"
45
- when 409
46
- raise Error, "Error 409: Your request was a conflict. '#{response.body["error"]["code"]}'"
47
- when 429
48
- raise Error, "Error 429: Your request exceeded the API rate limit. '#{response.body["error"]["code"]}'"
49
- when 500
50
- raise Error, "Error 500: We were unable to perform the request due to server-side problems. '#{response.body["error"]["code"]}'"
51
- when 503
52
- raise Error, "Error 503: You have been rate limited for sending more than 20 requests per second. '#{response.body["error"]["code"]}'"
53
- when 501
54
- raise Error, "Error 501: This resource has not been implemented. '#{response.body["error"]["code"]}'"
55
- when 204
56
- return true
57
- end
26
+ private
58
27
 
59
- if response.body && response.body["error"]
60
- raise Error, "Error #{response.body["error"]["code"]} - #{response.body["errors"]["message"]}"
28
+ def create_connection
29
+ Faraday.new(Paddle.config.url) do |conn|
30
+ conn.request :authorization, :Bearer, Paddle.config.api_key
31
+ conn.headers = default_headers
32
+ conn.request :json
33
+ conn.response :json
61
34
  end
35
+ end
36
+
37
+ def default_headers
38
+ {
39
+ "User-Agent" => "paddle/v#{VERSION} (github.com/deanpcmad/paddle)",
40
+ "Paddle-Version" => Paddle.config.version.to_s
41
+ }
42
+ end
43
+
44
+ def handle_response(response)
45
+ return true if response.status == 204
46
+ return response unless error?(response)
47
+
48
+ raise_error(response)
49
+ end
50
+
51
+ def error?(response)
52
+ [ 400, 401, 403, 404, 409, 429, 500, 501, 503 ].include?(response.status) ||
53
+ response.body&.key?("error")
54
+ end
62
55
 
63
- response
56
+ def raise_error(response)
57
+ error = Paddle::ErrorFactory.create(response.body, response.status)
58
+ raise error if error
64
59
  end
65
60
  end
66
61
  end
data/lib/paddle/error.rb CHANGED
@@ -1,4 +1,127 @@
1
1
  module Paddle
2
2
  class Error < StandardError
3
+ attr_reader :http_status_code
4
+ attr_reader :paddle_error_code
5
+ attr_reader :paddle_error_message
6
+
7
+ def initialize(response_body, http_status_code)
8
+ @response_body = response_body
9
+ @http_status_code = http_status_code
10
+ set_paddle_error_values
11
+ super(build_message)
12
+ end
13
+
14
+ private
15
+
16
+ def set_paddle_error_values
17
+ @paddle_error_code = @response_body.dig("error", "code")
18
+ @paddle_error_message = @response_body.dig("error", "detail")
19
+ end
20
+
21
+ def error_message
22
+ @paddle_error_message || @response_body.dig("error", "code")
23
+ rescue NoMethodError
24
+ "An unknown error occurred."
25
+ end
26
+
27
+ def build_message
28
+ if paddle_error_code.nil?
29
+ return "Error #{@http_status_code}: #{error_message}"
30
+ end
31
+ "Error #{@http_status_code}: #{error_message} '#{paddle_error_code}'"
32
+ end
33
+ end
34
+
35
+ class BadRequestError < Error
36
+ private
37
+
38
+ def error_message
39
+ "Your request was malformed."
40
+ end
41
+ end
42
+
43
+ class AuthenticationMissingError < Error
44
+ private
45
+
46
+ def error_message
47
+ "You did not supply valid authentication credentials."
48
+ end
49
+ end
50
+
51
+ class ForbiddenError < Error
52
+ private
53
+
54
+ def error_message
55
+ "You are not allowed to perform that action."
56
+ end
57
+ end
58
+
59
+ class EntityNotFoundError < Error
60
+ private
61
+
62
+ def error_message
63
+ "No results were found for your request."
64
+ end
65
+ end
66
+
67
+ class ConflictError < Error
68
+ private
69
+
70
+ def error_message
71
+ "Your request was a conflict."
72
+ end
73
+ end
74
+
75
+ class TooManyRequestsError < Error
76
+ private
77
+
78
+ def error_message
79
+ "Your request exceeded the API rate limit."
80
+ end
81
+ end
82
+
83
+ class InternalError < Error
84
+ private
85
+
86
+ def error_message
87
+ "We were unable to perform the request due to server-side problems."
88
+ end
89
+ end
90
+
91
+ class ServiceUnavailableError < Error
92
+ private
93
+
94
+ def error_message
95
+ "You have been rate limited for sending more than 20 requests per second."
96
+ end
97
+ end
98
+
99
+ class NotImplementedError < Error
100
+ private
101
+
102
+ def error_message
103
+ "This resource has not been implemented."
104
+ end
105
+ end
106
+
107
+
108
+ class ErrorFactory
109
+ HTTP_ERROR_MAP = {
110
+ 400 => BadRequestError,
111
+ 401 => AuthenticationMissingError,
112
+ 403 => ForbiddenError,
113
+ 404 => EntityNotFoundError,
114
+ 409 => ConflictError,
115
+ 429 => TooManyRequestsError,
116
+ 500 => InternalError,
117
+ 503 => ServiceUnavailableError,
118
+ 501 => NotImplementedError
119
+ }.freeze
120
+
121
+ def self.create(response_body, http_status_code)
122
+ status = http_status_code
123
+ error_class = HTTP_ERROR_MAP[status] || Error
124
+ error_class.new(response_body, http_status_code) if error_class
125
+ end
3
126
  end
4
127
  end
data/lib/paddle/object.rb CHANGED
@@ -15,5 +15,26 @@ module Paddle
15
15
  obj
16
16
  end
17
17
  end
18
+
19
+ def update(**params)
20
+ method_missing :update unless klass.respond_to? :update
21
+
22
+ primary_attributes = klass.method(:update).parameters.select { |(type, name)| type == :keyreq }.map(&:last) # Identified by whatever is a required named parameter.
23
+
24
+ primary_attributes.each do |attrib|
25
+ # ? Should we need to handle blank strings here?
26
+ params[attrib] = self[attrib] || self["#{attrib}_id"] # Handling for customer (customer_id) and id.
27
+ end
28
+
29
+ klass.public_send(:update, **params).each_pair { |key, val| self[key] = val } # Updating self
30
+
31
+ self
32
+ end
33
+
34
+ private
35
+
36
+ def klass
37
+ self.class
38
+ end
18
39
  end
19
40
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Paddle
4
- VERSION = "2.2.1"
4
+ VERSION = "2.3.0"
5
5
  end
data/lib/paddle.rb CHANGED
@@ -9,6 +9,8 @@ module Paddle
9
9
  autoload :Client, "paddle/client"
10
10
  autoload :Collection, "paddle/collection"
11
11
  autoload :Error, "paddle/error"
12
+ autoload :ErrorFactory, "paddle/error"
13
+
12
14
  autoload :Object, "paddle/object"
13
15
 
14
16
  class << self
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paddle
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dean Perry
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-28 00:00:00.000000000 Z
11
+ date: 2024-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -110,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
110
  - !ruby/object:Gem::Version
111
111
  version: '0'
112
112
  requirements: []
113
- rubygems_version: 3.5.9
113
+ rubygems_version: 3.5.15
114
114
  signing_key:
115
115
  specification_version: 4
116
116
  summary: Ruby library for the Paddle Billing & Classic APIs