payload-api 0.5.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.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/lib/payload/arm/attr.rb +169 -0
- data/lib/payload/arm/object.rb +37 -2
- data/lib/payload/arm/request.rb +57 -7
- data/lib/payload/arm/session.rb +8 -4
- data/lib/payload/exceptions.rb +15 -0
- data/lib/payload/objects.rb +10 -2
- data/lib/payload/version.rb +2 -2
- data/spec/payload/arm/arm_request_query_spec.rb +226 -0
- data/spec/payload/arm/attr_spec.rb +216 -0
- data/spec/payload/arm/object_spec.rb +114 -0
- data/spec/payload/arm/request_format_integration_spec.rb +166 -0
- data/spec/payload/arm/request_spec.rb +38 -1
- data/spec/payload/arm/session_spec.rb +40 -0
- data/spec/payload/exceptions_spec.rb +82 -0
- metadata +8 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a6364ada87b188e97370c985aaee315c1abe7149162d0bfe1a1feca21407e416
|
|
4
|
+
data.tar.gz: 0ba29b0d267e6dbe078c0ffe8a20ac915cfebb515e9ac20f6d7f8697160a45d5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d6e5b2ebca0650bc0358a0d8883681363a519795ffa49349fb936f821175d9d173f45ad49c86553ac701f3a284bfd48f8cdf901831fa7b559a7dc13c0f0adb07
|
|
7
|
+
data.tar.gz: 18634323e7c0221562430f79fc68638f2db08f2ee9caea5bb2b3c7b3f577aa2d8b70627ad17af9e3b72d2f9ed802ef211b69a2bc60566036b8922f3bb2b35b5b
|
data/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
The MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2026 Payload (http://payload.com)
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Payload
|
|
4
|
+
class ARMFilter
|
|
5
|
+
attr_reader :attr, :opval, :val
|
|
6
|
+
|
|
7
|
+
def initialize(attr, val)
|
|
8
|
+
@attr = attr.to_s
|
|
9
|
+
@val = val
|
|
10
|
+
@opval = self.class.op + val.to_s
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.op
|
|
14
|
+
''
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def |(other)
|
|
18
|
+
raise TypeError, 'invalid type' unless other.is_a?(Payload::ARMFilter)
|
|
19
|
+
raise ArgumentError, '`or` only works on the same attribute' if other.attr != @attr
|
|
20
|
+
joined = [@opval, other.opval].join('|')
|
|
21
|
+
Payload::ARMEqual.new(@attr, joined)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class ARMEqual < ARMFilter
|
|
26
|
+
def self.op
|
|
27
|
+
''
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class ARMNotEqual < ARMFilter
|
|
32
|
+
def self.op
|
|
33
|
+
'!'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class ARMGreaterThan < ARMFilter
|
|
38
|
+
def self.op
|
|
39
|
+
'>'
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class ARMLessThan < ARMFilter
|
|
44
|
+
def self.op
|
|
45
|
+
'<'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class ARMGreaterThanEqual < ARMFilter
|
|
50
|
+
def self.op
|
|
51
|
+
'>='
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class ARMLessThanEqual < ARMFilter
|
|
56
|
+
def self.op
|
|
57
|
+
'<='
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class ARMContains < ARMFilter
|
|
62
|
+
def self.op
|
|
63
|
+
'?*'
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Root proxy for pl.attr so that pl.attr.name returns an Attr (not Class#name).
|
|
68
|
+
# Session#attr returns this instead of the Attr class to avoid Class/Module methods (e.g. .name) shadowing attribute names.
|
|
69
|
+
class AttrRoot
|
|
70
|
+
def method_missing(name, *args)
|
|
71
|
+
if args.size == 1 && args[0].is_a?(Symbol)
|
|
72
|
+
inner = Attr.new(name.to_s)
|
|
73
|
+
Attr.new(args[0].to_s, inner).call
|
|
74
|
+
else
|
|
75
|
+
Attr.new(name.to_s)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def respond_to_missing?(name, include_private = false)
|
|
80
|
+
true
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Attribute DSL for select/group_by/order_by and filter expressions.
|
|
85
|
+
# - pl.attr.id -> "id"
|
|
86
|
+
# - pl.attr.created_at(:month) -> "month(created_at)"
|
|
87
|
+
# - pl.attr.amount(:sum) -> "sum(amount)"
|
|
88
|
+
# - pl.attr.sender.account_id -> "sender[account_id]"
|
|
89
|
+
class Attr
|
|
90
|
+
attr_reader :param, :parent
|
|
91
|
+
|
|
92
|
+
class << self
|
|
93
|
+
def method_missing(name, *args)
|
|
94
|
+
new(name.to_s)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def respond_to_missing?(name, include_private = false)
|
|
98
|
+
true
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def initialize(param, parent = nil)
|
|
103
|
+
@param = param.to_s
|
|
104
|
+
@parent = parent
|
|
105
|
+
@is_method = false
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def key
|
|
109
|
+
@parent ? "#{@parent.key}[#{@param}]" : @param
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def to_s
|
|
113
|
+
@is_method ? "#{@param}(#{@parent.key})" : key
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def strip
|
|
117
|
+
to_s.strip
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def method_missing(name, *args)
|
|
121
|
+
raise "cannot get attr of method" if @is_method
|
|
122
|
+
|
|
123
|
+
if args.size == 1 && args[0].is_a?(Symbol)
|
|
124
|
+
inner = Attr.new(name.to_s, self)
|
|
125
|
+
Attr.new(args[0].to_s, inner).call
|
|
126
|
+
else
|
|
127
|
+
Attr.new(name.to_s, self)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def respond_to_missing?(name, include_private = false)
|
|
132
|
+
true
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Mark attribute as a function call (e.g. .month(), .sum())
|
|
136
|
+
def call
|
|
137
|
+
@is_method = true
|
|
138
|
+
self
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def ==(other)
|
|
142
|
+
ARMEqual.new(self, other)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def !=(other)
|
|
146
|
+
ARMNotEqual.new(self, other)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def >(other)
|
|
150
|
+
ARMGreaterThan.new(self, other)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def <(other)
|
|
154
|
+
ARMLessThan.new(self, other)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def >=(other)
|
|
158
|
+
ARMGreaterThanEqual.new(self, other)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def <=(other)
|
|
162
|
+
ARMLessThanEqual.new(self, other)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def contains(other)
|
|
166
|
+
ARMContains.new(self, other)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
data/lib/payload/arm/object.rb
CHANGED
|
@@ -29,11 +29,26 @@ module Payload
|
|
|
29
29
|
def get(id)
|
|
30
30
|
return @cls.get(id, :session => @session)
|
|
31
31
|
end
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
def select(*args, **data)
|
|
34
34
|
@cls.select(*args, **data, session: @session)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
def order_by(*args, **data)
|
|
38
|
+
@cls.order_by(*args, **data, session: @session)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def limit(n, **data)
|
|
42
|
+
@cls.limit(n, **data, session: @session)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def offset(n, **data)
|
|
46
|
+
@cls.offset(n, **data, session: @session)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def group_by(*args, **data)
|
|
50
|
+
@cls.group_by(*args, **data, session: @session)
|
|
51
|
+
end
|
|
37
52
|
end
|
|
38
53
|
|
|
39
54
|
class ARMObject
|
|
@@ -103,7 +118,7 @@ module Payload
|
|
|
103
118
|
end
|
|
104
119
|
|
|
105
120
|
def [](key)
|
|
106
|
-
return @data[key]
|
|
121
|
+
return @data[key.to_s]
|
|
107
122
|
end
|
|
108
123
|
|
|
109
124
|
def _get_request()
|
|
@@ -118,6 +133,22 @@ module Payload
|
|
|
118
133
|
return self._get_request().select(*args, **data)
|
|
119
134
|
end
|
|
120
135
|
|
|
136
|
+
def self.order_by(*args, **data)
|
|
137
|
+
self._get_request().order_by(*args, **data)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def self.limit(n, **data)
|
|
141
|
+
self._get_request().limit(n)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def self.offset(n, **data)
|
|
145
|
+
self._get_request().offset(n)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def self.group_by(*args, **data)
|
|
149
|
+
self._get_request().group_by(*args, **data)
|
|
150
|
+
end
|
|
151
|
+
|
|
121
152
|
def self.filter_by(*args, **data)
|
|
122
153
|
session = data[:session]
|
|
123
154
|
data.delete(:session)
|
|
@@ -154,6 +185,10 @@ module Payload
|
|
|
154
185
|
return _get_request()._request('Delete', id: self.id)
|
|
155
186
|
end
|
|
156
187
|
|
|
188
|
+
def json
|
|
189
|
+
to_json
|
|
190
|
+
end
|
|
191
|
+
|
|
157
192
|
def to_json(*args)
|
|
158
193
|
serialized = {}
|
|
159
194
|
if self.class.poly
|
data/lib/payload/arm/request.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "payload/exceptions"
|
|
2
2
|
require "payload/utils"
|
|
3
|
+
require "payload/arm/attr"
|
|
3
4
|
require "net/http"
|
|
4
5
|
require "uri"
|
|
5
6
|
require "json"
|
|
@@ -12,21 +13,46 @@ module Payload
|
|
|
12
13
|
@cls = cls
|
|
13
14
|
@session = session || Payload::Session.new(Payload::api_key, Payload::api_url)
|
|
14
15
|
@filters = {}
|
|
16
|
+
@group_by = []
|
|
17
|
+
@order_by = []
|
|
18
|
+
@limit = nil
|
|
19
|
+
@offset = nil
|
|
20
|
+
@filter_objects = []
|
|
15
21
|
end
|
|
16
22
|
|
|
17
23
|
def select(*args, **data)
|
|
18
|
-
@filters['fields'] = args.map {|a| a.strip }.join(',')
|
|
19
|
-
|
|
24
|
+
@filters['fields'] = args.map { |a| a.strip }.join(',')
|
|
20
25
|
return self
|
|
21
26
|
end
|
|
22
27
|
|
|
28
|
+
def group_by(*args, **data)
|
|
29
|
+
@group_by.concat(args)
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def order_by(*args, **data)
|
|
34
|
+
@order_by.concat(args)
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def limit(n)
|
|
39
|
+
@limit = n
|
|
40
|
+
self
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def offset(n)
|
|
44
|
+
@offset = n
|
|
45
|
+
self
|
|
46
|
+
end
|
|
47
|
+
|
|
23
48
|
def filter_by(*args, **data)
|
|
49
|
+
args.each do |f|
|
|
50
|
+
@filter_objects << f if f.respond_to?(:attr) && f.respond_to?(:opval)
|
|
51
|
+
end
|
|
24
52
|
if !@cls.nil? && @cls.poly
|
|
25
53
|
data = data.merge(@cls.poly)
|
|
26
54
|
end
|
|
27
|
-
|
|
28
55
|
@filters = @filters.merge(data)
|
|
29
|
-
|
|
30
56
|
return self
|
|
31
57
|
end
|
|
32
58
|
|
|
@@ -35,6 +61,17 @@ module Payload
|
|
|
35
61
|
return self._request('Get')
|
|
36
62
|
end
|
|
37
63
|
|
|
64
|
+
def [](key)
|
|
65
|
+
case key
|
|
66
|
+
when Range
|
|
67
|
+
raise ArgumentError, 'Negative slice indices not supported' if key.begin && key.begin < 0
|
|
68
|
+
raise ArgumentError, 'Negative slice indices not supported' if key.end && key.end < 0
|
|
69
|
+
offset(key.begin).limit(key.size).all()
|
|
70
|
+
else
|
|
71
|
+
raise TypeError, "invalid key or index: #{key.inspect}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
38
75
|
def get(id)
|
|
39
76
|
if id.nil? || id.empty?
|
|
40
77
|
throw 'id cannot be empty'
|
|
@@ -127,17 +164,29 @@ module Payload
|
|
|
127
164
|
http.request(request)
|
|
128
165
|
end
|
|
129
166
|
|
|
167
|
+
def request_params
|
|
168
|
+
params = @filters.dup
|
|
169
|
+
@filter_objects.each { |f| params[f.attr] = f.opval }
|
|
170
|
+
@group_by.each_with_index { |v, i| params["group_by[#{i}]"] = v.to_s }
|
|
171
|
+
@order_by.each_with_index { |v, i| params["order_by[#{i}]"] = v.to_s }
|
|
172
|
+
params['limit'] = @limit.to_s if @limit
|
|
173
|
+
params['offset'] = @offset.to_s if @offset
|
|
174
|
+
params
|
|
175
|
+
end
|
|
176
|
+
|
|
130
177
|
def _request(method, id: nil, json: nil)
|
|
131
178
|
if !@cls.nil?
|
|
132
179
|
if @cls.spec.key?("endpoint")
|
|
133
180
|
endpoint = @cls.spec["endpoint"]
|
|
134
181
|
else
|
|
135
|
-
|
|
182
|
+
obj = @cls.spec["object"]
|
|
183
|
+
endpoint = "/" + (obj.end_with?("s") ? obj : obj + "s")
|
|
136
184
|
end
|
|
137
185
|
else
|
|
138
186
|
if json.is_a? Array
|
|
139
187
|
if json.all? {|obj| obj.key?("object") }
|
|
140
|
-
|
|
188
|
+
obj = json[0]["object"]
|
|
189
|
+
endpoint = (obj.end_with?("s") ? obj : obj + "s")
|
|
141
190
|
end
|
|
142
191
|
end
|
|
143
192
|
end
|
|
@@ -146,8 +195,9 @@ module Payload
|
|
|
146
195
|
endpoint = File.join(endpoint, id)
|
|
147
196
|
end
|
|
148
197
|
|
|
198
|
+
params = request_params
|
|
149
199
|
url = URI.join(@session.api_url, endpoint)
|
|
150
|
-
url.query = URI.encode_www_form(
|
|
200
|
+
url.query = URI.encode_www_form(params)
|
|
151
201
|
|
|
152
202
|
http = Net::HTTP.new(url.host, url.port)
|
|
153
203
|
|
data/lib/payload/arm/session.rb
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
require 'payload/arm/request'
|
|
2
|
-
|
|
2
|
+
require 'payload/arm/attr'
|
|
3
3
|
|
|
4
4
|
module Payload
|
|
5
5
|
class Session
|
|
6
6
|
attr_accessor :api_key, :api_url, :api_version
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
def initialize(api_key = nil, api_url = nil, api_version = nil, **kwargs)
|
|
9
9
|
@api_key = kwargs[:api_key] || api_key
|
|
10
10
|
@api_url = kwargs[:api_url] || api_url || Payload.URL
|
|
11
11
|
@api_version = kwargs[:api_version] || api_version || Payload.api_version
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
Payload.constants.each do |c|
|
|
14
14
|
val = Payload.const_get(c)
|
|
15
15
|
if val.is_a?(Class) && val < Payload::ARMObject
|
|
@@ -17,11 +17,15 @@ module Payload
|
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
def _get_request(cls = nil)
|
|
22
22
|
return Payload::ARMRequest.new(cls, self)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
def attr
|
|
26
|
+
Payload::AttrRoot.new
|
|
27
|
+
end
|
|
28
|
+
|
|
25
29
|
def query(cls)
|
|
26
30
|
return self._get_request(cls)
|
|
27
31
|
end
|
data/lib/payload/exceptions.rb
CHANGED
|
@@ -18,6 +18,21 @@ module Payload
|
|
|
18
18
|
@code='400'
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
class TransactionDeclined < BadRequest
|
|
22
|
+
attr_reader :transaction
|
|
23
|
+
|
|
24
|
+
def initialize(msg, data = nil)
|
|
25
|
+
super(msg, data)
|
|
26
|
+
@transaction = if data && data['details'].is_a?(Hash)
|
|
27
|
+
cls = Payload.get_cls(data['details'])
|
|
28
|
+
cls = Payload::Transaction if cls.nil?
|
|
29
|
+
cls.new(data['details'], nil)
|
|
30
|
+
else
|
|
31
|
+
nil
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
21
36
|
class InvalidAttributes < PayloadError
|
|
22
37
|
@code='400'
|
|
23
38
|
end
|
data/lib/payload/objects.rb
CHANGED
|
@@ -62,10 +62,18 @@ module Payload
|
|
|
62
62
|
@spec = { 'object' => 'invoice' }
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
+
class InvoiceAttachment < ARMObject
|
|
66
|
+
@spec = { 'object' => 'invoice_attachment' }
|
|
67
|
+
end
|
|
68
|
+
|
|
65
69
|
class PaymentActivation < ARMObject
|
|
66
70
|
@spec = { 'object' => 'payment_activation' }
|
|
67
71
|
end
|
|
68
72
|
|
|
73
|
+
class ProcessingSettings < ARMObject
|
|
74
|
+
@spec = { 'object' => 'processing_settings' }
|
|
75
|
+
end
|
|
76
|
+
|
|
69
77
|
class Webhook < ARMObject
|
|
70
78
|
@spec = { 'object' => 'webhook' }
|
|
71
79
|
end
|
|
@@ -96,7 +104,7 @@ module Payload
|
|
|
96
104
|
class ProcessingAccount < ARMObject
|
|
97
105
|
@spec = { 'object' => 'processing_account' }
|
|
98
106
|
end
|
|
99
|
-
|
|
107
|
+
|
|
100
108
|
class Org < ARMObject
|
|
101
109
|
@spec = { 'object' => 'org', 'endpoint' => '/account/orgs' }
|
|
102
110
|
end
|
|
@@ -123,7 +131,7 @@ module Payload
|
|
|
123
131
|
end
|
|
124
132
|
|
|
125
133
|
class Entity < ARMObject
|
|
126
|
-
@spec = { 'object' => 'entity' }
|
|
134
|
+
@spec = { 'object' => 'entity', 'endpoint' => 'entities' }
|
|
127
135
|
end
|
|
128
136
|
|
|
129
137
|
class Stakeholder < ARMObject
|
data/lib/payload/version.rb
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
module Payload
|
|
2
|
-
VERSION = '0.
|
|
3
|
-
end
|
|
2
|
+
VERSION = '0.6.1'
|
|
3
|
+
end
|