3scale_client 2.9.0 → 2.10.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 +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/3scale/client.rb +24 -9
- data/lib/3scale/client/http_client.rb +22 -10
- data/lib/3scale/client/version.rb +1 -1
- data/lib/3scale/rack_query.rb +37 -0
- data/test/client_test.rb +61 -2
- metadata +3 -3
- data/VERSION +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0c46a8b42107a91987d9861498f796287909fb5
|
4
|
+
data.tar.gz: 5d43b1ee44766fe2057fec8eea21f5a30a8ac83f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c3b09b26c8ec29367f68fc231b52c3d7af036d8360179b968d50d231a2a1332ba5b0c11139539e4af6a711cb2716fe47972eaa34e66fb4ba8addc29c876e33b
|
7
|
+
data.tar.gz: 3d3136b451d4694fc00291d013e07dd1fd562f4c605caf1bc32a7c4f1e5ca6c6bb9808eed46f54909d7e551fea5f7260363d6ef5c75aca9ef4f00b85f9d6c717
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## [2.10.0] - 2016-11-25
|
5
|
+
### Added
|
6
|
+
- Added support for 3scale extensions (experimental or non-standard
|
7
|
+
features that are not part of the official API). You just need to
|
8
|
+
add the `:extensions` symbol and the value to the hash of options that
|
9
|
+
the client methods accept. The value is itself a hash containing the
|
10
|
+
parameter names as keys and the parameter values as values.
|
11
|
+
|
4
12
|
## [2.9.0] - 2016-10-21
|
5
13
|
This version drops support for Ruby versions < 2.1 and JRuby < 9.1.1.0.
|
6
14
|
|
data/lib/3scale/client.rb
CHANGED
@@ -7,6 +7,7 @@ require '3scale/client/version'
|
|
7
7
|
|
8
8
|
require '3scale/response'
|
9
9
|
require '3scale/authorize_response'
|
10
|
+
require '3scale/rack_query'
|
10
11
|
|
11
12
|
module ThreeScale
|
12
13
|
Error = Class.new(RuntimeError)
|
@@ -47,6 +48,9 @@ module ThreeScale
|
|
47
48
|
'def report(transactions: [], service_id: nil).'.freeze
|
48
49
|
private_constant :DEPRECATION_MSG_OLD_REPORT
|
49
50
|
|
51
|
+
EXTENSIONS_HEADER = '3scale-options'.freeze
|
52
|
+
private_constant :EXTENSIONS_HEADER
|
53
|
+
|
50
54
|
def initialize(options)
|
51
55
|
if options[:provider_key].nil? || options[:provider_key] =~ /^\s*$/
|
52
56
|
raise ArgumentError, 'missing :provider_key'
|
@@ -69,6 +73,7 @@ module ThreeScale
|
|
69
73
|
|
70
74
|
options_usage = options.delete :usage
|
71
75
|
options_log = options.delete :log
|
76
|
+
extensions = options.delete :extensions
|
72
77
|
|
73
78
|
options.each_pair do |param, value|
|
74
79
|
path += "&#{param}=#{CGI.escape(value.to_s)}"
|
@@ -86,7 +91,8 @@ module ThreeScale
|
|
86
91
|
path += "&#{log.join('&')}"
|
87
92
|
end
|
88
93
|
|
89
|
-
|
94
|
+
headers = extensions_to_header extensions if extensions
|
95
|
+
http_response = @http.get(path, headers: headers)
|
90
96
|
|
91
97
|
case http_response
|
92
98
|
when Net::HTTPSuccess,Net::HTTPConflict
|
@@ -148,7 +154,7 @@ module ThreeScale
|
|
148
154
|
# The signature of this method is a bit complicated because we decided to
|
149
155
|
# keep backwards compatibility with a previous version of the method:
|
150
156
|
# def report(*transactions)
|
151
|
-
def report(*reports, transactions: [], service_id: nil, **rest)
|
157
|
+
def report(*reports, transactions: [], service_id: nil, extensions: nil, **rest)
|
152
158
|
if (!transactions || transactions.empty?) && rest.empty?
|
153
159
|
raise ArgumentError, 'no transactions to report'
|
154
160
|
end
|
@@ -164,7 +170,8 @@ module ThreeScale
|
|
164
170
|
payload['provider_key'] = CGI.escape(provider_key)
|
165
171
|
payload['service_id'] = CGI.escape(service_id.to_s) if service_id
|
166
172
|
|
167
|
-
|
173
|
+
headers = extensions_to_header extensions if extensions
|
174
|
+
http_response = @http.post('/transactions.xml', payload, headers: headers)
|
168
175
|
|
169
176
|
case http_response
|
170
177
|
when Net::HTTPSuccess
|
@@ -189,6 +196,7 @@ module ThreeScale
|
|
189
196
|
# usage:: predicted usage. It is optional. It is a hash where the keys are metrics
|
190
197
|
# and the values their predicted usage.
|
191
198
|
# Example: {'hits' => 1, 'my_metric' => 100}
|
199
|
+
# extensions:: Optional. Hash of extension keys and values.
|
192
200
|
#
|
193
201
|
# == Return
|
194
202
|
#
|
@@ -210,9 +218,11 @@ module ThreeScale
|
|
210
218
|
# end
|
211
219
|
#
|
212
220
|
def authorize(options)
|
221
|
+
extensions = options.delete :extensions
|
213
222
|
path = "/transactions/authorize.xml" + options_to_params(options, ALL_PARAMS)
|
214
223
|
|
215
|
-
|
224
|
+
headers = extensions_to_header extensions if extensions
|
225
|
+
http_response = @http.get(path, headers: headers)
|
216
226
|
|
217
227
|
case http_response
|
218
228
|
when Net::HTTPSuccess,Net::HTTPConflict
|
@@ -259,9 +269,11 @@ module ThreeScale
|
|
259
269
|
# end
|
260
270
|
#
|
261
271
|
def oauth_authorize(options)
|
272
|
+
extensions = options.delete :extensions
|
262
273
|
path = "/transactions/oauth_authorize.xml" + options_to_params(options, OAUTH_PARAMS)
|
263
274
|
|
264
|
-
|
275
|
+
headers = extensions_to_header extensions if extensions
|
276
|
+
http_response = @http.get(path, headers: headers)
|
265
277
|
|
266
278
|
case http_response
|
267
279
|
when Net::HTTPSuccess,Net::HTTPConflict
|
@@ -275,10 +287,8 @@ module ThreeScale
|
|
275
287
|
|
276
288
|
private
|
277
289
|
|
278
|
-
|
279
|
-
|
280
|
-
OAUTH_PARAMS = [:app_id, :app_key, :service_id, :redirect_url, :usage, :hierarchy]
|
281
|
-
ALL_PARAMS = [:user_key, :app_id, :app_key, :service_id, :redirect_url, :usage, :hierarchy]
|
290
|
+
OAUTH_PARAMS = [:app_id, :app_key, :service_id, :redirect_url, :usage]
|
291
|
+
ALL_PARAMS = [:user_key, :app_id, :app_key, :service_id, :redirect_url, :usage]
|
282
292
|
REPORT_PARAMS = [:user_key, :app_id, :service_id, :timestamp]
|
283
293
|
|
284
294
|
def options_to_params(options, allowed_keys)
|
@@ -382,5 +392,10 @@ module ThreeScale
|
|
382
392
|
response.error!(node.content.to_s.strip, node['code'].to_s.strip)
|
383
393
|
response
|
384
394
|
end
|
395
|
+
|
396
|
+
# Encode extensions header
|
397
|
+
def extensions_to_header(extensions)
|
398
|
+
{ EXTENSIONS_HEADER => RackQuery.encode(extensions) }
|
399
|
+
end
|
385
400
|
end
|
386
401
|
end
|
@@ -39,20 +39,32 @@ module ThreeScale
|
|
39
39
|
@port = port
|
40
40
|
end
|
41
41
|
|
42
|
-
def get_request(path)
|
42
|
+
def get_request(path, headers: nil)
|
43
43
|
get = Net::HTTP::Get.new(path)
|
44
44
|
get.add_field(*USER_CLIENT_HEADER)
|
45
45
|
get.add_field('Host', @host)
|
46
|
+
add_request_headers(get, headers) if headers
|
46
47
|
get
|
47
48
|
end
|
48
49
|
|
49
|
-
def post_request(path, payload)
|
50
|
+
def post_request(path, payload, headers: nil)
|
50
51
|
post = Net::HTTP::Post.new(path)
|
51
52
|
post.add_field(*USER_CLIENT_HEADER)
|
52
53
|
post.add_field('Host', @host)
|
54
|
+
add_request_headers(post, headers) if headers
|
53
55
|
post.set_form_data(payload)
|
54
56
|
post
|
55
57
|
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def add_request_headers(req, headers)
|
62
|
+
if headers
|
63
|
+
headers.each do |hk, hv|
|
64
|
+
req.add_field(hk, hv)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
56
68
|
end
|
57
69
|
|
58
70
|
class NetHttpPersistent < BaseClient
|
@@ -77,15 +89,15 @@ module ThreeScale
|
|
77
89
|
@protocol = 'https'
|
78
90
|
end
|
79
91
|
|
80
|
-
def get(path)
|
92
|
+
def get(path, headers: nil)
|
81
93
|
uri = full_uri(path)
|
82
|
-
@http.request(uri, get_request(path))
|
94
|
+
@http.request(uri, get_request(path, headers: headers))
|
83
95
|
end
|
84
96
|
|
85
97
|
|
86
|
-
def post(path, payload)
|
98
|
+
def post(path, payload, headers: nil)
|
87
99
|
uri = full_uri(path)
|
88
|
-
@http.request(uri, post_request(path, payload))
|
100
|
+
@http.request(uri, post_request(path, payload, headers: headers))
|
89
101
|
end
|
90
102
|
|
91
103
|
def full_uri(path)
|
@@ -107,12 +119,12 @@ module ThreeScale
|
|
107
119
|
@http.use_ssl = true
|
108
120
|
end
|
109
121
|
|
110
|
-
def get(path)
|
111
|
-
@http.request get_request(path)
|
122
|
+
def get(path, headers: nil)
|
123
|
+
@http.request get_request(path, headers: headers)
|
112
124
|
end
|
113
125
|
|
114
|
-
def post(path, payload)
|
115
|
-
@http.request post_request(path, payload)
|
126
|
+
def post(path, payload, headers: nil)
|
127
|
+
@http.request post_request(path, payload, headers: headers)
|
116
128
|
end
|
117
129
|
end
|
118
130
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# A simple module to encode hashes of param keys and values as expected by
|
2
|
+
# Rack in its nested queries parsing.
|
3
|
+
#
|
4
|
+
module RackQuery
|
5
|
+
class << self
|
6
|
+
def encode(hash)
|
7
|
+
hash.flat_map do |hk, hv|
|
8
|
+
encode_value(CGI.escape(hk.to_s), hv)
|
9
|
+
end.join('&'.freeze)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def encode_value(rack_param, val)
|
15
|
+
if val.is_a? Array
|
16
|
+
encode_array(rack_param, val)
|
17
|
+
elsif val.is_a? Hash
|
18
|
+
encode_hash(rack_param, val)
|
19
|
+
else
|
20
|
+
"#{rack_param}=#{CGI.escape(val.to_s)}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def encode_array(rack_param, val)
|
25
|
+
rack_param = rack_param + '[]'
|
26
|
+
val.flat_map do |v|
|
27
|
+
encode_value(rack_param, v)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def encode_hash(rack_param, val)
|
32
|
+
val.flat_map do |k, v|
|
33
|
+
encode_value(rack_param + "[#{CGI.escape(k.to_s)}]", v)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/test/client_test.rb
CHANGED
@@ -267,7 +267,7 @@ class ThreeScale::ClientTest < MiniTest::Test
|
|
267
267
|
# calls.
|
268
268
|
urls = [:authorize, :authrep, :oauth_authorize].inject({}) do |acc, method|
|
269
269
|
acc[method] = "http://#{@host}/transactions/#{method}.xml?"\
|
270
|
-
"provider_key=1234abcd&app_id=foo
|
270
|
+
"provider_key=1234abcd&app_id=foo"
|
271
271
|
acc[method] << "&%5Busage%5D%5Bhits%5D=1" if method == :authrep
|
272
272
|
acc
|
273
273
|
end
|
@@ -317,7 +317,7 @@ class ThreeScale::ClientTest < MiniTest::Test
|
|
317
317
|
|
318
318
|
urls.each do |method, url|
|
319
319
|
FakeWeb.register_uri(:get, url, :status => ['200', 'OK'], :body => body)
|
320
|
-
response = @client.send(method, :app_id => 'foo', :hierarchy => 1)
|
320
|
+
response = @client.send(method, :app_id => 'foo', extensions: { :hierarchy => 1 })
|
321
321
|
assert_equal response.hierarchy, { 'parent1' => ['child1', 'child2'],
|
322
322
|
'parent2' => ['child3'] }
|
323
323
|
end
|
@@ -702,6 +702,65 @@ class ThreeScale::ClientTest < MiniTest::Test
|
|
702
702
|
assert_equal "su1.3scale.net", request["host"]
|
703
703
|
end
|
704
704
|
|
705
|
+
EXTENSIONS_HASH = {
|
706
|
+
'a special &=key' => 'a special =&value',
|
707
|
+
'ary' => [1,2],
|
708
|
+
'a hash' => { one: 'one', two: 'two' },
|
709
|
+
'combined' =>
|
710
|
+
{ v: 'v', nested: [1, { h: [ { hh: [ { hhh: :deep }, 'val' ] } ], h2: :h2 } ] }
|
711
|
+
}
|
712
|
+
private_constant :EXTENSIONS_HASH
|
713
|
+
EXTENSIONS_STR = "a+special+%26%3Dkey=a+special+%3D%26value&ary[]=1&ary[]=2&" \
|
714
|
+
"a+hash[one]=one&a+hash[two]=two&combined[v]=v&" \
|
715
|
+
"combined[nested][]=1&combined[nested][][h][][hh][][hhh]=deep&" \
|
716
|
+
"combined[nested][][h][][hh][]=val&combined[nested][][h2]=h2".freeze
|
717
|
+
private_constant :EXTENSIONS_STR
|
718
|
+
|
719
|
+
def test_authorize_with_extensions
|
720
|
+
body = '<status>
|
721
|
+
<authorized>true</authorized>
|
722
|
+
<plan>Ultimate</plan>
|
723
|
+
</status>'
|
724
|
+
FakeWeb.register_uri(:get,
|
725
|
+
"http://#{@host}/transactions/authorize.xml?provider_key=1234abcd&app_id=foo",
|
726
|
+
:status => ['200', 'OK'], body: body)
|
727
|
+
|
728
|
+
@client.authorize(:app_id => 'foo', extensions: EXTENSIONS_HASH)
|
729
|
+
|
730
|
+
request = FakeWeb.last_request
|
731
|
+
assert_equal EXTENSIONS_STR, request[ThreeScale::Client.const_get('EXTENSIONS_HEADER')]
|
732
|
+
end
|
733
|
+
|
734
|
+
def test_authrep_with_extensions
|
735
|
+
body = '<status>
|
736
|
+
<authorized>true</authorized>
|
737
|
+
<plan>Ultimate</plan>
|
738
|
+
</status>'
|
739
|
+
FakeWeb.register_uri(:get,
|
740
|
+
"http://#{@host}/transactions/authrep.xml?provider_key=1234abcd&app_id=foo&%5Busage%5D%5Bhits%5D=1",
|
741
|
+
:status => ['200', 'OK'], body: body)
|
742
|
+
|
743
|
+
@client.authrep(:app_id => 'foo', extensions: EXTENSIONS_HASH)
|
744
|
+
|
745
|
+
request = FakeWeb.last_request
|
746
|
+
assert_equal EXTENSIONS_STR, request['3scale-options']
|
747
|
+
end
|
748
|
+
|
749
|
+
def test_report_with_extensions
|
750
|
+
FakeWeb.register_uri(:post, "http://#{@host}/transactions.xml",
|
751
|
+
:status => ['200', 'OK'])
|
752
|
+
|
753
|
+
transactions = [{ :app_id => 'app_id_1',
|
754
|
+
:usage => { 'hits' => 1 },
|
755
|
+
:timestamp => '2016-07-18 15:42:17 0200' }]
|
756
|
+
|
757
|
+
@client.report(transactions: transactions, service_id: 'a_service_id',
|
758
|
+
extensions: EXTENSIONS_HASH)
|
759
|
+
|
760
|
+
request = FakeWeb.last_request
|
761
|
+
assert_equal EXTENSIONS_STR, request['3scale-options']
|
762
|
+
end
|
763
|
+
|
705
764
|
private
|
706
765
|
|
707
766
|
#OPTIMIZE this tricky test helper relies on fakeweb catching the urls requested by the client
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: 3scale_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michal Cichra
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2016-
|
15
|
+
date: 2016-11-25 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: bundler
|
@@ -172,13 +172,13 @@ files:
|
|
172
172
|
- LICENCE
|
173
173
|
- README.md
|
174
174
|
- Rakefile
|
175
|
-
- VERSION
|
176
175
|
- gemfiles/rack_1.gemfile
|
177
176
|
- lib/3scale/authorize_response.rb
|
178
177
|
- lib/3scale/client.rb
|
179
178
|
- lib/3scale/client/http_client.rb
|
180
179
|
- lib/3scale/client/version.rb
|
181
180
|
- lib/3scale/middleware.rb
|
181
|
+
- lib/3scale/rack_query.rb
|
182
182
|
- lib/3scale/response.rb
|
183
183
|
- lib/3scale_client.rb
|
184
184
|
- test/benchmark.rb
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.8.2
|