adash 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/README.md +77 -5
- data/Rakefile +0 -3
- data/adash.gemspec +4 -4
- data/exe/adash +9 -2
- data/lib/adash/version.rb +1 -1
- metadata +13 -13
- data/.rspec +0 -2
- data/lib/adash/client.rb +0 -213
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 396638a8ef38f6b9167e149fa1fc627fccac9e61
|
4
|
+
data.tar.gz: a643cde5a6649f266ada88ebdc7f4f9530d75569
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4b4451e6cc62c73845cb62d694eb282bdc4f5d16a83e68a89cfa6e6fdffad16e4bc25f1b6aad19d87d7901d162dad57d4421d63f30722bd964e4203c42cc8e0
|
7
|
+
data.tar.gz: 8c54f4d2e1640c0da553f6aa381051a224dc572e25b61da71d42368cf66fdba54e97a1de3075d6dbee5fe04ba777ec0f52b33945e239a41ed6a9981dd00fb099
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -20,19 +20,91 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
+
### `adash init`
|
24
|
+
|
25
|
+
You can initialize with `adash init` sub-command. It takes `name` and `device_model` what likes `01234567-89ab-cdef-0123-456789abcdef`.
|
26
|
+
|
27
|
+
```bash
|
28
|
+
$ adash init lozenge 01234567-89ab-cdef-0123-456789abcdef
|
29
|
+
[2016-12-23 00:11:44] INFO WEBrick 1.3.1
|
30
|
+
[2016-12-23 00:11:44] INFO ruby 2.3.3 (2016-11-21) [x86_64-linux]
|
31
|
+
[2016-12-23 00:11:44] INFO WEBrick::HTTPServer#start: pid=11687 port=55582
|
32
|
+
...
|
33
|
+
```
|
34
|
+
|
35
|
+
WEBrick web server runs intenally, and a browser is opened for it.
|
36
|
+
You are requested OAuth authorization and DRS initialization.
|
37
|
+
|
38
|
+
### `adash list`
|
39
|
+
|
40
|
+
The sub-command `adash list` shows initialized devices list.
|
41
|
+
|
23
42
|
```bash
|
24
|
-
$ adash
|
43
|
+
$ adash list
|
44
|
+
---- name: lozenge
|
45
|
+
* device_model: 01234567-89ab-cdef-0123-456789abcdef
|
46
|
+
serial: d973f856-a21e-4701-bcfa-8e8eb8913c31_1482343916_3SVTiar3FX0CBnZW
|
47
|
+
---- name: jaga
|
48
|
+
* device_model: fedcba98-7654-3210-fedc-ba9876543210
|
49
|
+
serial: fbb51681-d087-4495-806e-c1f58ac59d4e_1482419498_afSWz8PqGgyqOqaH
|
25
50
|
```
|
26
51
|
|
27
|
-
|
52
|
+
### `adash list-slot`
|
53
|
+
|
54
|
+
```bash
|
55
|
+
$ adash list-slot lozenge
|
56
|
+
---- 0
|
57
|
+
* slot_id: 01a23b45-c56d-78e9-01a2-3b45c56d78e9
|
58
|
+
available: true
|
59
|
+
---- 1
|
60
|
+
* slot_id: 9e87d65c-54b3-2a10-9e87-d65c54b32a10
|
61
|
+
available: true
|
62
|
+
```
|
63
|
+
|
64
|
+
### `adash replenish`
|
65
|
+
|
66
|
+
```bash
|
67
|
+
$ adash replenish lozenge
|
68
|
+
|
69
|
+
---- number: 0
|
70
|
+
* slot_id: 01a23b45-c56d-78e9-01a2-3b45c56d78e9
|
71
|
+
available: true
|
72
|
+
|
28
73
|
|
29
|
-
|
74
|
+
---- number: 1
|
75
|
+
* slot_id: 9e87d65c-54b3-2a10-9e87-d65c54b32a10
|
76
|
+
available: true
|
30
77
|
|
31
|
-
|
78
|
+
Select slot number>
|
79
|
+
```
|
80
|
+
|
81
|
+
You should select replenish slot.
|
82
|
+
|
83
|
+
```bash
|
84
|
+
elect slot number> 1
|
85
|
+
Succeeded to order.
|
86
|
+
```
|
87
|
+
|
88
|
+
If the slot is already ordered, the message below is shown.
|
89
|
+
|
90
|
+
```bash
|
91
|
+
elect slot number> 1
|
92
|
+
The order is in progress.
|
93
|
+
```
|
94
|
+
|
95
|
+
There are no the selection prompts when the slot is just one.
|
96
|
+
|
97
|
+
### `adash deregistrate`
|
98
|
+
|
99
|
+
You can delete device from Adash and Amazon.
|
100
|
+
|
101
|
+
```bash
|
102
|
+
$ adash deregistrate lozenge
|
103
|
+
```
|
32
104
|
|
33
105
|
## Contributing
|
34
106
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
107
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/aycabta/adash.
|
36
108
|
|
37
109
|
|
38
110
|
## License
|
data/Rakefile
CHANGED
data/adash.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Code Ass"]
|
10
10
|
spec.email = ["aycabta@gmail.com"]
|
11
11
|
|
12
|
-
spec.summary = %q{Adash}
|
13
|
-
spec.description = %
|
12
|
+
spec.summary = %q{Adash is a Dash Replenishment Service CLI client}
|
13
|
+
spec.description = %Q{Adash is a Dash Replenishment Service CLI client.\nYou will login with OAuth (Login with Amazon) and replenish items.}
|
14
14
|
spec.homepage = "https://github.com/aycabta/adash"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
22
|
spec.add_development_dependency "bundler", "~> 1.13"
|
23
|
-
spec.add_development_dependency "rake", "~>
|
24
|
-
spec.add_development_dependency "
|
23
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
24
|
+
spec.add_development_dependency "amazon-drs"
|
25
25
|
spec.add_development_dependency "launchy", "~> 2.5"
|
26
26
|
end
|
data/exe/adash
CHANGED
@@ -9,6 +9,7 @@ require 'optparse'
|
|
9
9
|
require 'readline'
|
10
10
|
require 'fileutils'
|
11
11
|
require 'yaml'
|
12
|
+
require 'amazon-drs'
|
12
13
|
|
13
14
|
opt = OptionParser.new
|
14
15
|
|
@@ -60,12 +61,15 @@ def save_credentials_without_device_model(device_model)
|
|
60
61
|
end
|
61
62
|
|
62
63
|
def create_client_from_device(device)
|
63
|
-
|
64
|
+
AmazonDrs::Client.new(device['device_model']) do |c|
|
64
65
|
c.authorization_code = device['authorization_code']
|
65
66
|
c.serial = device['serial']
|
66
67
|
c.redirect_uri = device['redirect_uri']
|
67
68
|
c.access_token = device['access_token']
|
68
69
|
c.refresh_token = device['refresh_token']
|
70
|
+
c.client_id = Adash::Config.client_id
|
71
|
+
c.client_secret = Adash::Config.client_secret
|
72
|
+
c.redirect_uri = "http://localhost:#{Adash::Config.redirect_port}/"
|
69
73
|
c.on_new_token = proc { |access_token, refresh_token|
|
70
74
|
credentials = get_credentials
|
71
75
|
updated_device = get_device_from_credentials(credentials, device['device_model'])
|
@@ -101,7 +105,10 @@ end
|
|
101
105
|
|
102
106
|
def select_slot_prompt(client)
|
103
107
|
resp = client.subscription_info
|
104
|
-
slots = resp.json['slotsSubscriptionStatus']
|
108
|
+
slots = resp.json['slotsSubscriptionStatus'].select{ |k, v| v }
|
109
|
+
if slots.size == 1
|
110
|
+
return slots.keys.first
|
111
|
+
end
|
105
112
|
loop do
|
106
113
|
show_slots(slots)
|
107
114
|
slot_num = Readline.readline('Select slot number> ')
|
data/lib/adash/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code Ass
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -30,28 +30,28 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '12.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '12.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: amazon-drs
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: launchy
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,7 +66,9 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '2.5'
|
69
|
-
description:
|
69
|
+
description: |-
|
70
|
+
Adash is a Dash Replenishment Service CLI client.
|
71
|
+
You will login with OAuth (Login with Amazon) and replenish items.
|
70
72
|
email:
|
71
73
|
- aycabta@gmail.com
|
72
74
|
executables:
|
@@ -75,7 +77,6 @@ extensions: []
|
|
75
77
|
extra_rdoc_files: []
|
76
78
|
files:
|
77
79
|
- ".gitignore"
|
78
|
-
- ".rspec"
|
79
80
|
- ".travis.yml"
|
80
81
|
- Gemfile
|
81
82
|
- LICENSE.txt
|
@@ -87,7 +88,6 @@ files:
|
|
87
88
|
- data/client
|
88
89
|
- exe/adash
|
89
90
|
- lib/adash.rb
|
90
|
-
- lib/adash/client.rb
|
91
91
|
- lib/adash/config.rb
|
92
92
|
- lib/adash/version.rb
|
93
93
|
- lib/adash/wait_indefinitely.rb
|
@@ -114,5 +114,5 @@ rubyforge_project:
|
|
114
114
|
rubygems_version: 2.5.2
|
115
115
|
signing_key:
|
116
116
|
specification_version: 4
|
117
|
-
summary: Adash
|
117
|
+
summary: Adash is a Dash Replenishment Service CLI client
|
118
118
|
test_files: []
|
data/.rspec
DELETED
data/lib/adash/client.rb
DELETED
@@ -1,213 +0,0 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
require 'uri'
|
3
|
-
require 'json'
|
4
|
-
require 'yaml'
|
5
|
-
require 'time'
|
6
|
-
require 'date'
|
7
|
-
require 'adash/config'
|
8
|
-
|
9
|
-
class Net::HTTPResponse
|
10
|
-
attr_accessor :json
|
11
|
-
end
|
12
|
-
|
13
|
-
module Adash
|
14
|
-
class Client
|
15
|
-
attr_accessor :device_model, :serial, :authorization_code, :redirect_uri, :access_token, :refresh_token
|
16
|
-
attr_accessor :on_new_token
|
17
|
-
attr_writer :user_agent
|
18
|
-
|
19
|
-
def initialize(device_model)
|
20
|
-
@drs_host = 'dash-replenishment-service-na.amazon.com'
|
21
|
-
@amazon_host = 'api.amazon.com'
|
22
|
-
@device_model = device_model
|
23
|
-
@serial = nil
|
24
|
-
@authorization_code = nil
|
25
|
-
@redirect_uri = nil
|
26
|
-
@access_token = nil
|
27
|
-
@refresh_token = nil
|
28
|
-
@on_new_token = nil
|
29
|
-
yield(self) if block_given?
|
30
|
-
end
|
31
|
-
|
32
|
-
def user_agent
|
33
|
-
@user_agent ||= "AdashRubyGem/#{Adash::VERSION}/#{RUBY_DESCRIPTION}"
|
34
|
-
end
|
35
|
-
|
36
|
-
def deregistrate_device
|
37
|
-
headers = {
|
38
|
-
'x-amzn-accept-type': 'com.amazon.dash.replenishment.DrsDeregisterResult@1.0',
|
39
|
-
'x-amzn-type-version': 'com.amazon.dash.replenishment.DrsDeregisterInput@1.0'
|
40
|
-
}
|
41
|
-
path = "/deviceModels/#{@device_model}/devices/#{@serial}/registration"
|
42
|
-
request_drs(:delete, path, headers: headers)
|
43
|
-
end
|
44
|
-
|
45
|
-
def device_status(most_recently_active_date)
|
46
|
-
headers = {
|
47
|
-
'x-amzn-accept-type': 'com.amazon.dash.replenishment.DrsDeviceStatusResult@1.0',
|
48
|
-
'x-amzn-type-version': 'com.amazon.dash.replenishment.DrsDeviceStatusInput@1.0'
|
49
|
-
}
|
50
|
-
path = '/deviceStatus'
|
51
|
-
request_drs(:post, path, headers: headers, params: { 'mostRecentlyActiveDate' => convert_to_iso8601(most_recently_active_date) })
|
52
|
-
end
|
53
|
-
|
54
|
-
def subscription_info
|
55
|
-
headers = {
|
56
|
-
'x-amzn-accept-type': 'com.amazon.dash.replenishment.DrsSubscriptionInfoResult@1.0',
|
57
|
-
'x-amzn-type-version': 'com.amazon.dash.replenishment.DrsSubscriptionInfoInput@1.0'
|
58
|
-
}
|
59
|
-
path = '/subscriptionInfo'
|
60
|
-
request_drs(:get, path, headers: headers)
|
61
|
-
end
|
62
|
-
|
63
|
-
def slot_status(slot_id, expected_replenishment_date, remaining_quantity_in_unit, original_quantity_in_unit, total_quantity_on_hand, last_use_date)
|
64
|
-
headers = {
|
65
|
-
'x-amzn-accept-type': 'com.amazon.dash.replenishment.DrsSlotStatusResult@1.0',
|
66
|
-
'x-amzn-type-version': 'com.amazon.dash.replenishment.DrsSlotStatusInput@1.0'
|
67
|
-
}
|
68
|
-
path = "/slotStatus/#{slot_id}"
|
69
|
-
params = {
|
70
|
-
'expectedReplenishmentDate' => convert_to_iso8601(expected_replenishment_date),
|
71
|
-
'remainingQuantityInUnit' => remaining_quantity_in_unit,
|
72
|
-
'originalQuantityInUnit' => original_quantity_in_unit,
|
73
|
-
'totalQuantityOnHand' => total_quantity_on_hand,
|
74
|
-
'lastUseDate' => convert_to_iso8601(last_use_date)
|
75
|
-
}
|
76
|
-
request_drs(:post, path, headers: headers, params: params)
|
77
|
-
end
|
78
|
-
|
79
|
-
def replenish(slot_id)
|
80
|
-
headers = {
|
81
|
-
'x-amzn-accept-type': 'com.amazon.dash.replenishment.DrsReplenishResult@1.0',
|
82
|
-
'x-amzn-type-version': 'com.amazon.dash.replenishment.DrsReplenishInput@1.0'
|
83
|
-
}
|
84
|
-
path = "/replenish/#{slot_id}"
|
85
|
-
response = request_drs(:post, path, headers: headers)
|
86
|
-
# TODO: imprement response processing
|
87
|
-
# https://developer.amazon.com/public/solutions/devices/dash-replenishment-service/docs/dash-replenish-endpoint
|
88
|
-
# response examples:
|
89
|
-
# {"message":"Unable to place order - slot : <01234567-89ab-cdef-0123-456789abcdef> is unsubscribed."}
|
90
|
-
# {"detailCode":"STANDARD_ORDER_PLACED","eventInstanceId":"amzn1.dash.v2.o.xxxxxx......"}
|
91
|
-
# {"detailCode":"ORDER_INPROGRESS","eventInstanceId":"amzn1.dash.v2.o.xxxxxx......"}
|
92
|
-
end
|
93
|
-
|
94
|
-
def get_token
|
95
|
-
if @access_token
|
96
|
-
@access_token
|
97
|
-
else
|
98
|
-
resp = request_token
|
99
|
-
process_token_response(resp)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
private
|
104
|
-
|
105
|
-
def convert_to_iso8601(input)
|
106
|
-
case input
|
107
|
-
when Date, Time
|
108
|
-
input.iso8601
|
109
|
-
when String
|
110
|
-
input
|
111
|
-
else
|
112
|
-
input.to_s
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def process_token_response(resp)
|
117
|
-
if resp.json['error']
|
118
|
-
puts resp.json['error']
|
119
|
-
puts resp.json['error_description']
|
120
|
-
nil
|
121
|
-
else
|
122
|
-
@access_token = resp.json['access_token']
|
123
|
-
@refresh_token = resp.json['refresh_token']
|
124
|
-
@on_new_token.call(@access_token, @refresh_token) if @on_new_token
|
125
|
-
@access_token
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def request_drs(method, path, headers: {}, params: {})
|
130
|
-
url = "https://#{@drs_host}#{path}"
|
131
|
-
if @authorization_code.nil?
|
132
|
-
raise 'Authorization Code is not set'
|
133
|
-
end
|
134
|
-
if @access_token.nil?
|
135
|
-
token = get_token
|
136
|
-
if token.nil?
|
137
|
-
raise 'Failed to get token'
|
138
|
-
end
|
139
|
-
end
|
140
|
-
resp = request(method, url, headers: headers, params: params)
|
141
|
-
if resp.code == '400' && resp.json['message'] == 'Invalid token' && @refresh_token
|
142
|
-
resp = refresh_access_token
|
143
|
-
process_token_response(resp)
|
144
|
-
request(method, url, headers: headers, params: params)
|
145
|
-
else
|
146
|
-
resp
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def refresh_access_token
|
151
|
-
params = {
|
152
|
-
grant_type: 'refresh_token',
|
153
|
-
refresh_token: @refresh_token,
|
154
|
-
client_id: Adash::Config.client_id,
|
155
|
-
client_secret: Adash::Config.client_secret
|
156
|
-
}
|
157
|
-
@access_token = nil
|
158
|
-
request(:post, "https://#{@amazon_host}/auth/o2/token", params: params)
|
159
|
-
end
|
160
|
-
|
161
|
-
def request_token
|
162
|
-
params = {
|
163
|
-
grant_type: 'authorization_code',
|
164
|
-
code: @authorization_code,
|
165
|
-
client_id: Adash::Config.client_id,
|
166
|
-
client_secret: Adash::Config.client_secret,
|
167
|
-
redirect_uri: "http://localhost:#{Adash::Config.redirect_port}/"
|
168
|
-
}
|
169
|
-
request(:post, "https://#{@amazon_host}/auth/o2/token", params: params)
|
170
|
-
end
|
171
|
-
|
172
|
-
def request(method, url, headers: {}, params: {})
|
173
|
-
uri = URI.parse(url)
|
174
|
-
if params.any?{ |key, value| value.is_a?(Enumerable) }
|
175
|
-
converted_params = []
|
176
|
-
params.each do |key, value|
|
177
|
-
if value.is_a?(Enumerable)
|
178
|
-
value.each_index do |i|
|
179
|
-
converted_params << ["#{key}[#{i}]", value[i]]
|
180
|
-
end
|
181
|
-
else
|
182
|
-
converted_params << [key, value]
|
183
|
-
end
|
184
|
-
end
|
185
|
-
params = converted_params
|
186
|
-
end
|
187
|
-
case method
|
188
|
-
when :delete
|
189
|
-
uri.query = URI.encode_www_form(params)
|
190
|
-
request = Net::HTTP::Delete.new(uri)
|
191
|
-
when :get
|
192
|
-
uri.query = URI.encode_www_form(params)
|
193
|
-
request = Net::HTTP::Get.new(uri)
|
194
|
-
when :post
|
195
|
-
request = Net::HTTP::Post.new(uri.path)
|
196
|
-
request.body = URI.encode_www_form(params)
|
197
|
-
end
|
198
|
-
request['Content-Type'] = 'application/x-www-form-urlencoded'
|
199
|
-
request['User-Agent'] = @user_agent
|
200
|
-
headers.each do |key, value|
|
201
|
-
request[key] = value
|
202
|
-
end
|
203
|
-
if not @access_token.nil?
|
204
|
-
request["Authorization"] = "Bearer #{@access_token}"
|
205
|
-
end
|
206
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
207
|
-
http.use_ssl = true
|
208
|
-
response = http.request(request)
|
209
|
-
response.json = JSON.parse(response.body)
|
210
|
-
response
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|