shoptet 0.0.3 → 0.0.8
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/README.md +2 -3
- data/lib/shoptet.rb +127 -62
- data/lib/shoptet/request.rb +20 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 020dcc94bd92d287243ac40e3bf854a9f0e5f4c32670fe221aa7af1a6b785e39
|
4
|
+
data.tar.gz: 5d3701df86ba602c16e626b7f703b01c733ef6878a3cfa862217c17cad19890e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b060e7a30c1cd96da7f7978231f40648b6a738154a33b0c6b5d8be538edd7e0f2dbfaa29490a16e979337244e9bd432b69e2a0cb3cc604a36d4354ba6c20e3a1
|
7
|
+
data.tar.gz: '0599e14ba6550168b2b02b31a8b25cb1452d244e27acb358d7a858473033c6992e0dec4a4cf28cf04d46d6c83c82ee4e06d54a0d00e7a2dc1e4afdda06827cb1'
|
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# Shoptet
|
2
2
|
|
3
|
-
This is Ruby API wrapper for [Shoptet API](https://
|
4
|
-
|
5
|
-
This is currently under development and hasn't been released to Rubygems yet.
|
3
|
+
This is Ruby API wrapper for [Shoptet API](https://shoptet.docs.apiary.io) which provides access to e-shop data for addon developers.
|
6
4
|
|
7
5
|
# How to install
|
8
6
|
|
@@ -82,6 +80,7 @@ Also they accept hash with params which will be passed to Shoptet api. Through t
|
|
82
80
|
## Other
|
83
81
|
|
84
82
|
* `Shoptet#new_api_token` - this returns new api token created with oauth token
|
83
|
+
* `Shoptet::install` - TODO
|
85
84
|
|
86
85
|
## License
|
87
86
|
|
data/lib/shoptet.rb
CHANGED
@@ -1,24 +1,72 @@
|
|
1
|
+
require 'delegate'
|
1
2
|
require_relative 'shoptet/request'
|
2
3
|
|
3
4
|
class Shoptet
|
4
|
-
|
5
|
-
#TODO: check that this works
|
6
|
-
attr_reader :additional_data
|
5
|
+
include Shoptet::UrlHelpers
|
7
6
|
|
8
|
-
|
9
|
-
super(message)
|
10
|
-
@additional_data = additional_data
|
11
|
-
end
|
12
|
-
end
|
7
|
+
class Error < StandardError; end
|
13
8
|
class AddonSuspended < StandardError; end
|
14
9
|
class AddonNotInstalled < StandardError; end
|
10
|
+
class InvalidTokenNoRights < StandardError; end
|
15
11
|
|
16
12
|
DEFAULT_ON_TOKEN_ERROR = -> (api) do
|
17
13
|
api.api_token = api.new_api_token
|
18
14
|
end
|
19
15
|
|
16
|
+
class ApiEnumerator < SimpleDelegator
|
17
|
+
def initialize base_url, filters, data_key, api
|
18
|
+
@base_url = base_url
|
19
|
+
@filters = filters
|
20
|
+
@data_key = data_key || URI(base_url).path.split('/').last
|
21
|
+
@api = api
|
22
|
+
|
23
|
+
@enum = Enumerator.new do |y|
|
24
|
+
first_page.dig('data', @data_key).each { y.yield _1 }
|
25
|
+
|
26
|
+
if total_pages > 1
|
27
|
+
other_pages = 2..(total_pages - 1)
|
28
|
+
other_pages.each do |page|
|
29
|
+
uri = @api.assemble_uri base_url, filters.merge(page: page)
|
30
|
+
result = @api.request uri
|
31
|
+
result.dig('data', @data_key).each { y.yield _1 }
|
32
|
+
end
|
33
|
+
|
34
|
+
last_page.dig('data', @data_key).each { y.yield _1 }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
super @enum
|
39
|
+
end
|
40
|
+
|
41
|
+
def first_page
|
42
|
+
@first_page ||=
|
43
|
+
begin
|
44
|
+
uri = @api.assemble_uri @base_url, @filters
|
45
|
+
@api.request uri
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def total_pages
|
50
|
+
first_page.dig('data', 'paginator', 'pageCount') || 0
|
51
|
+
end
|
52
|
+
|
53
|
+
def last_page
|
54
|
+
return first_page if total_pages < 2
|
55
|
+
|
56
|
+
@last_page ||=
|
57
|
+
begin
|
58
|
+
uri = @api.assemble_uri @base_url, @filters.merge(page: total_pages)
|
59
|
+
@api.request uri
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def size
|
64
|
+
first_page['data']['paginator']['totalCount']
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
20
68
|
def self.version
|
21
|
-
'0.0.
|
69
|
+
'0.0.8'
|
22
70
|
end
|
23
71
|
|
24
72
|
def self.ar_on_token_error(model)
|
@@ -38,20 +86,71 @@ class Shoptet
|
|
38
86
|
end
|
39
87
|
end
|
40
88
|
|
89
|
+
def self.install url, redirect_url, client_id, client_secret, code
|
90
|
+
data = {
|
91
|
+
'redirect_uri' => redirect_url,
|
92
|
+
'client_id' => client_id,
|
93
|
+
'client_secret' => client_secret,
|
94
|
+
'code' => code,
|
95
|
+
'grant_type' => 'authorization_code',
|
96
|
+
'scope' => 'api'
|
97
|
+
}
|
98
|
+
|
99
|
+
Shoptet::Request.post url, data
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.login_token url, code, client_id, client_secret, redirect_url
|
103
|
+
data = {
|
104
|
+
code: code,
|
105
|
+
grant_type: 'authorization_code',
|
106
|
+
client_id: client_id,
|
107
|
+
client_secret: client_secret,
|
108
|
+
redirect_uri: redirect_url,
|
109
|
+
scope: 'basic_eshop'
|
110
|
+
}
|
111
|
+
|
112
|
+
Shoptet::Request.post url, data
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.basic_eshop url, access_token
|
116
|
+
Shoptet::Request.get url, { 'Authorization' => "Bearer #{access_token}" }
|
117
|
+
end
|
118
|
+
|
41
119
|
attr_accessor :api_token
|
42
120
|
|
43
|
-
def initialize
|
121
|
+
def initialize oauth_url:, oauth_token:, shop_url:, client_id:, api_token: nil, on_token_error: nil
|
44
122
|
@oauth_url = oauth_url
|
45
123
|
@oauth_token = oauth_token
|
124
|
+
@shop_url = shop_url
|
125
|
+
@client_id = client_id
|
46
126
|
@api_token = api_token
|
47
127
|
@on_token_error = on_token_error || DEFAULT_ON_TOKEN_ERROR
|
48
128
|
end
|
49
129
|
|
130
|
+
def authorize_url redirect_url, state
|
131
|
+
query = {
|
132
|
+
client_id: @client_id,
|
133
|
+
state: state,
|
134
|
+
scope: 'basic_eshop',
|
135
|
+
response_type: 'code',
|
136
|
+
redirect_uri: redirect_url
|
137
|
+
}.to_query
|
138
|
+
|
139
|
+
URI("#{@shop_url}action/OAuthServer/authorize?#{query}").to_s
|
140
|
+
end
|
141
|
+
|
50
142
|
def shop_info api_params = {}
|
51
|
-
request 'https://api.myshoptet.com/api/eshop'
|
143
|
+
result = request 'https://api.myshoptet.com/api/eshop'
|
144
|
+
result['data']
|
145
|
+
end
|
146
|
+
|
147
|
+
def design_info api_params = {}
|
148
|
+
result = request 'https://api.myshoptet.com/api/eshop/design'
|
149
|
+
|
150
|
+
result['data']
|
52
151
|
end
|
53
152
|
|
54
|
-
def
|
153
|
+
def stocks api_params = {}
|
55
154
|
enumerize 'https://api.myshoptet.com/api/stocks', api_params
|
56
155
|
end
|
57
156
|
|
@@ -64,6 +163,11 @@ class Shoptet
|
|
64
163
|
enumerize uri, api_params
|
65
164
|
end
|
66
165
|
|
166
|
+
def stocks_movements warehouse_id, api_params = {}
|
167
|
+
uri = "https://api.myshoptet.com/api/stocks/#{warehouse_id}/movements"
|
168
|
+
enumerize uri, api_params
|
169
|
+
end
|
170
|
+
|
67
171
|
def product_categories api_params = {}
|
68
172
|
enumerize 'https://api.myshoptet.com/api/categories', api_params
|
69
173
|
end
|
@@ -94,13 +198,13 @@ class Shoptet
|
|
94
198
|
def order code, api_params = {}
|
95
199
|
uri = "https://api.myshoptet.com/api/orders/#{code}"
|
96
200
|
result = request assemble_uri(uri, api_params)
|
97
|
-
result.dig
|
201
|
+
result.dig 'data', 'order'
|
98
202
|
end
|
99
203
|
|
100
204
|
def product guid, api_params = {}
|
101
205
|
uri = "https://api.myshoptet.com/api/products/#{guid}"
|
102
206
|
result = request assemble_uri(uri, api_params)
|
103
|
-
result
|
207
|
+
result['data']
|
104
208
|
end
|
105
209
|
|
106
210
|
def new_api_token
|
@@ -112,35 +216,6 @@ class Shoptet
|
|
112
216
|
result.fetch 'access_token'
|
113
217
|
end
|
114
218
|
|
115
|
-
private
|
116
|
-
|
117
|
-
def assemble_uri base, params = {}
|
118
|
-
u = URI(base)
|
119
|
-
u.query = URI.encode_www_form(params) if params.any?
|
120
|
-
|
121
|
-
u.to_s
|
122
|
-
end
|
123
|
-
|
124
|
-
def enumerize base_uri, filters = {}, data_key = nil
|
125
|
-
data_key ||= URI(base_uri).path.split('/').last
|
126
|
-
uri = assemble_uri base_uri, filters
|
127
|
-
size_proc = -> () { request(uri)['data']['paginator']['totalCount'] }
|
128
|
-
|
129
|
-
Enumerator.new(size_proc) do |y|
|
130
|
-
first_page = request uri
|
131
|
-
total_pages = first_page.dig('data', 'paginator', 'pageCount') || 0
|
132
|
-
other_pages = 2..total_pages
|
133
|
-
|
134
|
-
first_page.dig('data', data_key).each { y.yield _1.merge(page_url: uri) }
|
135
|
-
|
136
|
-
other_pages.each do |page|
|
137
|
-
uri = assemble_uri base_uri, filters.merge(page: page)
|
138
|
-
result = request uri
|
139
|
-
result.dig('data', data_key).each { y.yield _1.merge(page_url: uri) }
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
219
|
def request uri, retry_on_token_error = true
|
145
220
|
headers = { 'Shoptet-Access-Token' => @api_token,
|
146
221
|
'Content-Type' => 'application/vnd.shoptet.v1.0' }
|
@@ -160,6 +235,12 @@ class Shoptet
|
|
160
235
|
end
|
161
236
|
end
|
162
237
|
|
238
|
+
private
|
239
|
+
|
240
|
+
def enumerize base_url, filters = {}, data_key = nil
|
241
|
+
ApiEnumerator.new base_url, filters, data_key, self
|
242
|
+
end
|
243
|
+
|
163
244
|
def handle_errors result, uri, headers
|
164
245
|
error = result['error']
|
165
246
|
errors = result['errors'] || []
|
@@ -170,29 +251,13 @@ class Shoptet
|
|
170
251
|
raise AddonSuspended
|
171
252
|
elsif error == 'addon_not_installed'
|
172
253
|
raise AddonNotInstalled
|
254
|
+
elsif errors.any? { |err| err["errorCode"] == 'invalid-token-no-rights' }
|
255
|
+
raise InvalidTokenNoRights
|
173
256
|
else
|
174
|
-
|
175
|
-
uri: uri,
|
176
|
-
headers: scrub_sensitive_headers(headers)
|
177
|
-
}
|
178
|
-
|
179
|
-
raise Error.new result, additional_data
|
257
|
+
raise Error.new result
|
180
258
|
end
|
181
259
|
end
|
182
260
|
|
183
261
|
token_errors
|
184
262
|
end
|
185
|
-
|
186
|
-
def scrub_sensitive_headers headers
|
187
|
-
scrubbed = {}
|
188
|
-
|
189
|
-
to_scrub = ['Shoptet-Access-Token', 'Authorization']
|
190
|
-
to_scrub.each do |header|
|
191
|
-
if headers[header]
|
192
|
-
scrubbed[header] = "#{headers[header][0..20]}..."
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
headers.merge scrubbed
|
197
|
-
end
|
198
263
|
end
|
data/lib/shoptet/request.rb
CHANGED
@@ -3,6 +3,15 @@ require 'net/http'
|
|
3
3
|
#TODO: keep_alive_timeout ?
|
4
4
|
|
5
5
|
class Shoptet
|
6
|
+
module UrlHelpers
|
7
|
+
def assemble_uri base, params = {}
|
8
|
+
u = URI(base)
|
9
|
+
u.query = URI.encode_www_form(params) if params.any?
|
10
|
+
|
11
|
+
u.to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
6
15
|
class Request
|
7
16
|
def self.get uri, headers
|
8
17
|
attempt ||= 0
|
@@ -28,5 +37,16 @@ class Shoptet
|
|
28
37
|
rescue Net::OpenTimeout
|
29
38
|
retry if attempt < 4
|
30
39
|
end
|
40
|
+
|
41
|
+
def self.post uri, body
|
42
|
+
req = Net::HTTP::Post.new uri
|
43
|
+
req.set_form_data body
|
44
|
+
|
45
|
+
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
46
|
+
http.request req
|
47
|
+
end
|
48
|
+
|
49
|
+
JSON.parse res.body
|
50
|
+
end
|
31
51
|
end
|
32
52
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shoptet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Premysl Donat
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-11-
|
11
|
+
date: 2020-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: irb
|