muffin_man 1.1.0 → 1.4.0
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 +1 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +3 -0
- data/README.md +27 -3
- data/lib/muffin_man/authorization/v1.rb +16 -0
- data/lib/muffin_man/finances/v0.rb +14 -9
- data/lib/muffin_man/lwa/auth_helper.rb +27 -0
- data/lib/muffin_man/reports/v20210630.rb +1 -1
- data/lib/muffin_man/solicitations/v1.rb +4 -2
- data/lib/muffin_man/sp_api_client.rb +62 -28
- data/lib/muffin_man/version.rb +1 -1
- data/lib/muffin_man.rb +2 -0
- data/muffin_man.gemspec +1 -0
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1034d149292cba5172729ff270ccb038a70c6dcf1b5a9d460add8b7b370f0dea
|
4
|
+
data.tar.gz: 4d99306ee66d36d0df05bcd46e4d71a4af2db29b3a2d5562b37d5634b7722469
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e0faedca6d800deb56277c05103859cbdc2ceaebb80ec811ecab69e49d280913e37ecd09630d35bb95ae291e446b71d054877e4b7a6ca245c59b6797e1988a0
|
7
|
+
data.tar.gz: 34a92f83302a0f1945f1887bbac28e97c2150d734efffcdba648f91fa42aa5ba89e164f1005460694676c100d6ead10eee9177ca1df88055066acb5efb49e204
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -40,6 +40,7 @@ credentials = {
|
|
40
40
|
aws_secret_access_key: AWS_SECRET_ACCESS_KEY,
|
41
41
|
region: REGION, # This can be one of ['na', 'eu', 'fe'] and defaults to 'na'
|
42
42
|
sts_iam_role_arn: STS_IAM_ROLE_ARN, # Optional
|
43
|
+
access_token_cache_key: SELLING_PARTNER_ID, # Optional if you want access token caching
|
43
44
|
}
|
44
45
|
client = MuffinMan::Solicitations::V1.new(credentials)
|
45
46
|
response = client.create_product_review_and_seller_feedback_solicitation(amazon_order_id, marketplace_ids)
|
@@ -48,6 +49,8 @@ JSON.parse(response.body)
|
|
48
49
|
|
49
50
|
You can optionally use Amazon's sandbox environment by specifying `client = MuffinMan::Solicitations.new(credentials, sandbox = true)`
|
50
51
|
|
52
|
+
### Access Token Caching
|
53
|
+
|
51
54
|
You can save and retrieve the LWA refresh token by defining a lambda in your initializers.
|
52
55
|
|
53
56
|
For example, if you are using Redis as your cache you could define:
|
@@ -55,14 +58,35 @@ For example, if you are using Redis as your cache you could define:
|
|
55
58
|
```ruby
|
56
59
|
@@redis = Redis.new
|
57
60
|
MuffinMan.configure do |config|
|
58
|
-
config.save_access_token = -> (
|
59
|
-
@@redis.set("SP-TOKEN-#{
|
61
|
+
config.save_access_token = -> (access_token_cache_key, token) do
|
62
|
+
@@redis.set("SP-TOKEN-#{access_token_cache_key}", token['access_token'], ex: token['expires_in'])
|
60
63
|
end
|
61
64
|
|
62
|
-
config.get_access_token = -> (
|
65
|
+
config.get_access_token = -> (access_token_cache_key) { @@redis.get("SP-TOKEN-#{access_token_cache_key}") }
|
63
66
|
end
|
64
67
|
```
|
65
68
|
|
69
|
+
### Retrieiving the refresh token
|
70
|
+
|
71
|
+
To retrieve the refresh token from an LWA Website authorization workflow, you can use the LWA helper:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
# Get your auth code first, either through the Website oauth flow or Authorization API
|
75
|
+
credentials = {
|
76
|
+
client_id: CLIENT_ID,
|
77
|
+
client_secret: CLIENT_SECRET,
|
78
|
+
aws_access_key_id: AWS_ACCESS_KEY_ID,
|
79
|
+
aws_secret_access_key: AWS_SECRET_ACCESS_KEY,
|
80
|
+
sts_iam_role_arn: STS_IAM_ROLE_ARN, # Optional
|
81
|
+
scope: 'sellingpartnerapi::migration' # Grantless scope for MWS migration
|
82
|
+
}
|
83
|
+
client = MuffinMan::Authorization::V1.new(credentials)
|
84
|
+
resp = JSON.parse(client.get_authorization_code(seller_id, developer_id, mws_auth_token).body)
|
85
|
+
auth_code = resp['payload']['authorizationCode']
|
86
|
+
# Then query retrieve the refresh token to store
|
87
|
+
refresh_token = MuffinMan::Lwa::AuthHelper.get_refresh_token(CLIENT_ID, CLIENT_SECRET, auth_code)
|
88
|
+
```
|
89
|
+
|
66
90
|
## Contributing
|
67
91
|
|
68
92
|
Bug reports and pull requests are welcome on GitHub at https://github.com/patterninc/muffin_man. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/patterninc/muffin_man/blob/master/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module MuffinMan
|
2
|
+
module Authorization
|
3
|
+
class V1 < SpApiClient
|
4
|
+
def get_authorization_code(selling_partner_id, developer_id, mws_auth_token)
|
5
|
+
@query_params = {
|
6
|
+
"sellingPartnerId" => selling_partner_id,
|
7
|
+
"developerId" => developer_id,
|
8
|
+
"mwsAuthToken" => mws_auth_token
|
9
|
+
}
|
10
|
+
@request_type = "GET"
|
11
|
+
@local_var_path = "/authorization/v1/authorizationCode"
|
12
|
+
call_api
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,14 +1,19 @@
|
|
1
1
|
module MuffinMan
|
2
2
|
module Finances
|
3
3
|
class V0 < SpApiClient
|
4
|
-
|
5
4
|
def list_financial_event_groups(max_results_per_page = nil, financial_event_group_started_before = nil, financial_event_group_started_after = nil, next_token = nil)
|
6
5
|
@local_var_path = "/finances/v0/financialEventGroups"
|
7
6
|
@query_params = {}
|
8
|
-
@query_params[
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
@query_params["MaxResultsPerPage"] = max_results_per_page unless max_results_per_page.nil?
|
8
|
+
unless financial_event_group_started_before.nil?
|
9
|
+
@query_params["FinancialEventGroupStartedBefore"] =
|
10
|
+
financial_event_group_started_before
|
11
|
+
end
|
12
|
+
unless financial_event_group_started_after.nil?
|
13
|
+
@query_params["FinancialEventGroupStartedAfter"] =
|
14
|
+
financial_event_group_started_after
|
15
|
+
end
|
16
|
+
@query_params["NextToken"] = next_token unless next_token.nil?
|
12
17
|
@request_type = "GET"
|
13
18
|
call_api
|
14
19
|
end
|
@@ -16,10 +21,10 @@ module MuffinMan
|
|
16
21
|
def list_financial_events_by_group_id(event_group_id, max_results_per_page = nil, posted_after = nil, posted_before = nil, next_token = nil)
|
17
22
|
@local_var_path = "/finances/v0/financialEventGroups/#{event_group_id}/financialEvents"
|
18
23
|
@query_params = {}
|
19
|
-
@query_params[
|
20
|
-
@query_params[
|
21
|
-
@query_params[
|
22
|
-
@query_params[
|
24
|
+
@query_params["MaxResultsPerPage"] = max_results_per_page unless max_results_per_page.nil?
|
25
|
+
@query_params["PostedAfter"] = posted_after unless posted_after.nil?
|
26
|
+
@query_params["PostedBefore"] = posted_before unless posted_before.nil?
|
27
|
+
@query_params["NextToken"] = next_token unless next_token.nil?
|
23
28
|
@request_type = "GET"
|
24
29
|
call_api
|
25
30
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module MuffinMan::Lwa
|
2
|
+
class AuthHelper
|
3
|
+
ACCESS_TOKEN_URL = "https://api.amazon.com/auth/o2/token".freeze
|
4
|
+
|
5
|
+
def self.get_refresh_token(client_id, client_secret, auth_code)
|
6
|
+
body = {
|
7
|
+
grant_type: "authorization_code",
|
8
|
+
code: auth_code,
|
9
|
+
client_id: client_id,
|
10
|
+
client_secret: client_secret
|
11
|
+
}
|
12
|
+
response = Typhoeus.post(
|
13
|
+
ACCESS_TOKEN_URL,
|
14
|
+
body: URI.encode_www_form(body),
|
15
|
+
headers: {
|
16
|
+
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
|
17
|
+
}
|
18
|
+
)
|
19
|
+
if response.code != 200
|
20
|
+
error_body = JSON.parse(response.body)
|
21
|
+
error = "#{error_body["error"]}: #{error_body["error_description"]}"
|
22
|
+
raise MuffinMan::Error, error
|
23
|
+
end
|
24
|
+
JSON.parse(response.body)["refresh_token"]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -44,7 +44,7 @@ module MuffinMan
|
|
44
44
|
@local_var_path = "/reports/2021-06-30/reports"
|
45
45
|
@request_body = {
|
46
46
|
"reportType" => report_type,
|
47
|
-
"marketplaceIds" => marketplace_ids
|
47
|
+
"marketplaceIds" => marketplace_ids
|
48
48
|
}
|
49
49
|
@request_body["dataStartTime"] = start_time unless start_time.nil?
|
50
50
|
@request_body["dataEndTime"] = end_time unless end_time.nil?
|
@@ -11,9 +11,11 @@ module MuffinMan
|
|
11
11
|
def create_product_review_and_seller_feedback_solicitation(amazon_order_id, marketplace_ids)
|
12
12
|
@amazon_order_id = sandbox ? SANDBOX_AMAZON_ORDER_ID : amazon_order_id
|
13
13
|
@marketplace_ids = sandbox ? SANDBOX_MARKETPLACE_IDS : marketplace_ids
|
14
|
-
@local_var_path =
|
14
|
+
@local_var_path = "/solicitations/v1/orders/{amazonOrderId}/solicitations/productReviewAndSellerFeedback".sub(
|
15
|
+
"{" + "amazonOrderId" + "}", @amazon_order_id
|
16
|
+
)
|
15
17
|
@query_params = { "marketplaceIds" => @marketplace_ids }
|
16
|
-
@request_type =
|
18
|
+
@request_type = "POST"
|
17
19
|
call_api
|
18
20
|
end
|
19
21
|
end
|
@@ -1,20 +1,22 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
require "aws-sigv4"
|
2
|
+
require "uri"
|
3
|
+
require "aws-sdk-core"
|
4
|
+
require "typhoeus"
|
5
|
+
require "securerandom"
|
6
6
|
|
7
7
|
module MuffinMan
|
8
8
|
class SpApiClient
|
9
9
|
attr_reader :refresh_token, :client_id, :client_secret, :aws_access_key_id,
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
:aws_secret_access_key, :sts_iam_role_arn, :sandbox, :config,
|
11
|
+
:region, :request_type, :local_var_path, :query_params,
|
12
|
+
:request_body, :scope, :access_token_cache_key
|
13
|
+
|
14
|
+
ACCESS_TOKEN_URL = "https://api.amazon.com/auth/o2/token".freeze
|
15
|
+
SERVICE_NAME = "execute-api".freeze
|
14
16
|
AWS_REGION_MAP = {
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
"na" => "us-east-1",
|
18
|
+
"eu" => "eu-west-1",
|
19
|
+
"fe" => "us-west-2"
|
18
20
|
}.freeze
|
19
21
|
|
20
22
|
def initialize(credentials, sandbox = false)
|
@@ -24,9 +26,11 @@ module MuffinMan
|
|
24
26
|
@aws_access_key_id = credentials[:aws_access_key_id]
|
25
27
|
@aws_secret_access_key = credentials[:aws_secret_access_key]
|
26
28
|
@sts_iam_role_arn = credentials[:sts_iam_role_arn]
|
27
|
-
@region = credentials[:region] ||
|
29
|
+
@region = credentials[:region] || "na"
|
30
|
+
@scope = credentials[:scope]
|
31
|
+
@access_token_cache_key = credentials[:access_token_cache_key]
|
28
32
|
@sandbox = sandbox
|
29
|
-
Typhoeus::Config.user_agent =
|
33
|
+
Typhoeus::Config.user_agent = ""
|
30
34
|
@config = MuffinMan.configuration
|
31
35
|
end
|
32
36
|
|
@@ -38,9 +42,7 @@ module MuffinMan
|
|
38
42
|
|
39
43
|
def request_opts
|
40
44
|
opts = { headers: headers }
|
41
|
-
if request_body
|
42
|
-
opts[:body] = request_body.to_json
|
43
|
-
end
|
45
|
+
opts[:body] = request_body.to_json if request_body
|
44
46
|
opts
|
45
47
|
end
|
46
48
|
|
@@ -63,20 +65,25 @@ module MuffinMan
|
|
63
65
|
end
|
64
66
|
|
65
67
|
def retrieve_lwa_access_token
|
66
|
-
return request_lwa_access_token[
|
67
|
-
|
68
|
+
return request_lwa_access_token["access_token"] unless use_cache?
|
69
|
+
|
70
|
+
stored_token = config.get_access_token.call(access_token_cache_key)
|
68
71
|
if stored_token.nil?
|
69
72
|
new_token = request_lwa_access_token
|
70
|
-
config.save_access_token.call(
|
71
|
-
|
73
|
+
config.save_access_token.call(access_token_cache_key, new_token)
|
74
|
+
new_token["access_token"]
|
72
75
|
else
|
73
|
-
|
76
|
+
stored_token
|
74
77
|
end
|
75
78
|
end
|
76
79
|
|
80
|
+
def use_cache?
|
81
|
+
defined?(config.save_access_token) && defined?(config.get_access_token) && access_token_cache_key
|
82
|
+
end
|
83
|
+
|
77
84
|
def request_lwa_access_token
|
78
85
|
body = {
|
79
|
-
grant_type:
|
86
|
+
grant_type: "refresh_token",
|
80
87
|
refresh_token: refresh_token,
|
81
88
|
client_id: client_id,
|
82
89
|
client_secret: client_secret
|
@@ -85,7 +92,29 @@ module MuffinMan
|
|
85
92
|
ACCESS_TOKEN_URL,
|
86
93
|
body: URI.encode_www_form(body),
|
87
94
|
headers: {
|
88
|
-
|
95
|
+
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
|
96
|
+
}
|
97
|
+
)
|
98
|
+
JSON.parse(response.body)
|
99
|
+
end
|
100
|
+
|
101
|
+
def retrieve_grantless_access_token
|
102
|
+
# No storage of this type for now
|
103
|
+
request_grantless_access_token["access_token"]
|
104
|
+
end
|
105
|
+
|
106
|
+
def request_grantless_access_token
|
107
|
+
body = {
|
108
|
+
grant_type: "client_credentials",
|
109
|
+
scope: scope,
|
110
|
+
client_id: client_id,
|
111
|
+
client_secret: client_secret
|
112
|
+
}
|
113
|
+
response = Typhoeus.post(
|
114
|
+
ACCESS_TOKEN_URL,
|
115
|
+
body: URI.encode_www_form(body),
|
116
|
+
headers: {
|
117
|
+
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
|
89
118
|
}
|
90
119
|
)
|
91
120
|
JSON.parse(response.body)
|
@@ -117,17 +146,22 @@ module MuffinMan
|
|
117
146
|
end
|
118
147
|
|
119
148
|
def headers
|
149
|
+
access_token = scope ? retrieve_grantless_access_token : retrieve_lwa_access_token
|
120
150
|
headers = {
|
121
|
-
|
122
|
-
|
123
|
-
|
151
|
+
"x-amz-access-token" => access_token,
|
152
|
+
"user-agent" => "MuffinMan/#{VERSION} (Language=Ruby)",
|
153
|
+
"content-type" => "application/json"
|
124
154
|
}
|
125
155
|
signed_request.headers.merge(headers)
|
126
156
|
end
|
127
157
|
|
128
158
|
def derive_aws_region
|
129
159
|
@aws_region ||= AWS_REGION_MAP[region]
|
130
|
-
|
160
|
+
unless @aws_region
|
161
|
+
raise MuffinMan::Error,
|
162
|
+
"#{region} is not supported or does not exist. Region must be one of the following: #{AWS_REGION_MAP.keys.join(", ")}"
|
163
|
+
end
|
164
|
+
|
131
165
|
@aws_region
|
132
166
|
end
|
133
167
|
end
|
data/lib/muffin_man/version.rb
CHANGED
data/lib/muffin_man.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require "muffin_man/version"
|
2
2
|
require "muffin_man/sp_api_client"
|
3
|
+
require "muffin_man/lwa/auth_helper"
|
3
4
|
require "muffin_man/solicitations/v1"
|
4
5
|
require "muffin_man/reports/v20210630"
|
5
6
|
require "muffin_man/catalog_items/v20201201"
|
6
7
|
require "muffin_man/finances/v0"
|
8
|
+
require "muffin_man/authorization/v1"
|
7
9
|
|
8
10
|
module MuffinMan
|
9
11
|
class Error < StandardError; end
|
data/muffin_man.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency "rspec", "~> 3.2"
|
22
22
|
spec.add_development_dependency 'webmock', '~> 2.1'
|
23
|
+
spec.add_development_dependency 'byebug'
|
23
24
|
spec.add_development_dependency 'mock_redis', '>=0.14'
|
24
25
|
spec.add_runtime_dependency 'typhoeus', '~> 1.0', '>= 1.0.1'
|
25
26
|
spec.add_runtime_dependency 'aws-sigv4', '>= 1.1'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: muffin_man
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gavin
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2022-
|
13
|
+
date: 2022-05-03 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -40,6 +40,20 @@ dependencies:
|
|
40
40
|
- - "~>"
|
41
41
|
- !ruby/object:Gem::Version
|
42
42
|
version: '2.1'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: byebug
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
43
57
|
- !ruby/object:Gem::Dependency
|
44
58
|
name: mock_redis
|
45
59
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,6 +129,7 @@ files:
|
|
115
129
|
- ".gitignore"
|
116
130
|
- ".rspec"
|
117
131
|
- ".rubocop.yml"
|
132
|
+
- CHANGELOG.md
|
118
133
|
- CODE_OF_CONDUCT.md
|
119
134
|
- Gemfile
|
120
135
|
- LICENSE.txt
|
@@ -123,8 +138,10 @@ files:
|
|
123
138
|
- bin/console
|
124
139
|
- bin/setup
|
125
140
|
- lib/muffin_man.rb
|
141
|
+
- lib/muffin_man/authorization/v1.rb
|
126
142
|
- lib/muffin_man/catalog_items/v20201201.rb
|
127
143
|
- lib/muffin_man/finances/v0.rb
|
144
|
+
- lib/muffin_man/lwa/auth_helper.rb
|
128
145
|
- lib/muffin_man/reports/v20210630.rb
|
129
146
|
- lib/muffin_man/solicitations/v1.rb
|
130
147
|
- lib/muffin_man/sp_api_client.rb
|
@@ -149,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
149
166
|
- !ruby/object:Gem::Version
|
150
167
|
version: '0'
|
151
168
|
requirements: []
|
152
|
-
rubygems_version: 3.
|
169
|
+
rubygems_version: 3.2.22
|
153
170
|
signing_key:
|
154
171
|
specification_version: 4
|
155
172
|
summary: Amazon Selling Partner API client
|