shoptet 0.0.4 → 0.0.9

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 +134 -64
  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: 5a9b1eead75d41dcb892b89c4ce0c3d35a2dad76fccd58cf0dff5aa8c5d77dea
4
- data.tar.gz: 77cda0d0b883f5e6132f879f26a55adfb7cae835aa230584bd89ed83050b3c70
3
+ metadata.gz: 8b98a4b88e59f4cd33fcddb5448caae903e5cbeb81b8bda9fcf9c52a7db337aa
4
+ data.tar.gz: d138e3406b01db0f8b4833aeb3ac2b16a1b590341922d9d50e370774ef2de8bf
5
5
  SHA512:
6
- metadata.gz: 7d81e028c0f8f819a6a27cdc4c05e7a945572f13a0723f258af5da96139c8e4d94d46efac8e22542fe5ad9c0119d385000060257a98ba12cbd7db1378feaa224
7
- data.tar.gz: 10495eb6e0f391f8d14fa0cb1e1729e0c12a0d7c2a26ace5be79feef0e7cbdf4ae6a4299d45066936de5f2ecee0b5859e9cbd546db09e90071a4dafef085c9e7
6
+ metadata.gz: 91e5a23fb8973e97536947176590811e58c216a3b3a7e43cec2b57eadd9bbaafbc7a93e00bd761530853a351dc7fb6328ea8aac47f174cb876d7161de27136d6
7
+ data.tar.gz: a74007a4120bbd10f7be9e9ad1f95cfa474290bf2900eac5fcd0702f01588c2d369775b270848d2b285b03f17f3531e64747539a44841aaba9ee51d7a9b1d105
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.4'
69
+ '0.0.9'
22
70
  end
23
71
 
24
72
  def self.ar_on_token_error(model)
@@ -38,25 +86,81 @@ 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
 
50
- #TODO: return ['data'] already
130
+ def endpoints api_params = {}
131
+ enumerize 'https://api.myshoptet.com/api/system/endpoints', api_params
132
+ end
133
+
134
+ def endpoint_approved? endpoint
135
+ @approved_endpoints ||= endpoints
136
+
137
+ @approved_endpoints.any? { _1['endpoint'] == endpoint }
138
+ end
139
+
140
+ def authorize_url redirect_url, state
141
+ query = {
142
+ client_id: @client_id,
143
+ state: state,
144
+ scope: 'basic_eshop',
145
+ response_type: 'code',
146
+ redirect_uri: redirect_url
147
+ }.to_query
148
+
149
+ URI("#{@shop_url}action/OAuthServer/authorize?#{query}").to_s
150
+ end
151
+
51
152
  def shop_info api_params = {}
52
- request 'https://api.myshoptet.com/api/eshop'
153
+ result = request 'https://api.myshoptet.com/api/eshop'
154
+ result['data']
53
155
  end
54
156
 
55
157
  def design_info api_params = {}
56
- request 'https://api.myshoptet.com/api/eshop/design'
158
+ result = request 'https://api.myshoptet.com/api/eshop/design'
159
+
160
+ result['data']
57
161
  end
58
162
 
59
- def warehouses api_params = {}
163
+ def stocks api_params = {}
60
164
  enumerize 'https://api.myshoptet.com/api/stocks', api_params
61
165
  end
62
166
 
@@ -69,6 +173,11 @@ class Shoptet
69
173
  enumerize uri, api_params
70
174
  end
71
175
 
176
+ def stocks_movements warehouse_id, api_params = {}
177
+ uri = "https://api.myshoptet.com/api/stocks/#{warehouse_id}/movements"
178
+ enumerize uri, api_params
179
+ end
180
+
72
181
  def product_categories api_params = {}
73
182
  enumerize 'https://api.myshoptet.com/api/categories', api_params
74
183
  end
@@ -99,13 +208,13 @@ class Shoptet
99
208
  def order code, api_params = {}
100
209
  uri = "https://api.myshoptet.com/api/orders/#{code}"
101
210
  result = request assemble_uri(uri, api_params)
102
- result.dig('data', 'order')
211
+ result.dig 'data', 'order'
103
212
  end
104
213
 
105
214
  def product guid, api_params = {}
106
215
  uri = "https://api.myshoptet.com/api/products/#{guid}"
107
216
  result = request assemble_uri(uri, api_params)
108
- result.dig('data')
217
+ result['data']
109
218
  end
110
219
 
111
220
  def new_api_token
@@ -117,35 +226,6 @@ class Shoptet
117
226
  result.fetch 'access_token'
118
227
  end
119
228
 
120
- private
121
-
122
- def assemble_uri base, params = {}
123
- u = URI(base)
124
- u.query = URI.encode_www_form(params) if params.any?
125
-
126
- u.to_s
127
- end
128
-
129
- def enumerize base_uri, filters = {}, data_key = nil
130
- data_key ||= URI(base_uri).path.split('/').last
131
- uri = assemble_uri base_uri, filters
132
- size_proc = -> () { request(uri)['data']['paginator']['totalCount'] }
133
-
134
- Enumerator.new(size_proc) do |y|
135
- first_page = request uri
136
- total_pages = first_page.dig('data', 'paginator', 'pageCount') || 0
137
- other_pages = 2..total_pages
138
-
139
- first_page.dig('data', data_key).each { y.yield _1 }
140
-
141
- other_pages.each do |page|
142
- uri = assemble_uri base_uri, filters.merge(page: page)
143
- result = request uri
144
- result.dig('data', data_key).each { y.yield _1 }
145
- end
146
- end
147
- end
148
-
149
229
  def request uri, retry_on_token_error = true
150
230
  headers = { 'Shoptet-Access-Token' => @api_token,
151
231
  'Content-Type' => 'application/vnd.shoptet.v1.0' }
@@ -165,6 +245,12 @@ class Shoptet
165
245
  end
166
246
  end
167
247
 
248
+ private
249
+
250
+ def enumerize base_url, filters = {}, data_key = nil
251
+ ApiEnumerator.new base_url, filters, data_key, self
252
+ end
253
+
168
254
  def handle_errors result, uri, headers
169
255
  error = result['error']
170
256
  errors = result['errors'] || []
@@ -175,29 +261,13 @@ class Shoptet
175
261
  raise AddonSuspended
176
262
  elsif error == 'addon_not_installed'
177
263
  raise AddonNotInstalled
264
+ elsif errors.any? { |err| err["errorCode"] == 'invalid-token-no-rights' }
265
+ raise InvalidTokenNoRights
178
266
  else
179
- additional_data = {
180
- uri: uri,
181
- headers: scrub_sensitive_headers(headers)
182
- }
183
-
184
- raise Error.new result, additional_data
267
+ raise Error.new result
185
268
  end
186
269
  end
187
270
 
188
271
  token_errors
189
272
  end
190
-
191
- def scrub_sensitive_headers headers
192
- scrubbed = {}
193
-
194
- to_scrub = ['Shoptet-Access-Token', 'Authorization']
195
- to_scrub.each do |header|
196
- if headers[header]
197
- scrubbed[header] = "#{headers[header][0..20]}..."
198
- end
199
- end
200
-
201
- headers.merge scrubbed
202
- end
203
273
  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.4
4
+ version: 0.0.9
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-09 00:00:00.000000000 Z
11
+ date: 2020-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: irb