shoptet 0.0.3 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -3
  3. data/lib/shoptet.rb +127 -62
  4. data/lib/shoptet/request.rb +20 -0
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 682cc8f11ec548207514c501fb63e2c18ea8f9cb3a7ff4eb6db35b458b75b022
4
- data.tar.gz: ec70519cd497dd8a49e9c72ee1940ec084fa0a2203889de3292febb658885c1a
3
+ metadata.gz: 020dcc94bd92d287243ac40e3bf854a9f0e5f4c32670fe221aa7af1a6b785e39
4
+ data.tar.gz: 5d3701df86ba602c16e626b7f703b01c733ef6878a3cfa862217c17cad19890e
5
5
  SHA512:
6
- metadata.gz: 2ce582d9fdbac257cffd92e2b9cb60ac718141af95a2a744ad27605c35c883bbd82f9838deb9b1fde57802a37740f49309ac034b541b19ad2557e41b09ca0bbc
7
- data.tar.gz: 0bc005b177781df29dd9c7b0471d317ed108529b717455bd70a88bbb3ccbdc8b303bbd1ff21e9c2e7cb834a969876de547eecd86d17cddf32a80cfa473fe297a
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://developers.shoptet.com/) which provides access to e-shop data for addon developers.
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
 
@@ -1,24 +1,72 @@
1
+ require 'delegate'
1
2
  require_relative 'shoptet/request'
2
3
 
3
4
  class Shoptet
4
- class Error < StandardError
5
- #TODO: check that this works
6
- attr_reader :additional_data
5
+ include Shoptet::UrlHelpers
7
6
 
8
- def initialize message, additional_data = {}
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.3'
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(oauth_url, oauth_token, api_token = nil, on_token_error = nil)
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 warehouses api_params = {}
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('data', 'order').merge(detail_url: uri)
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.dig('data')
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
- additional_data = {
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
@@ -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.3
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-08 00:00:00.000000000 Z
11
+ date: 2020-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: irb