adash 0.0.1 → 0.0.2
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/.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
|