blurb 0.3.2 → 0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: bb4aebb3a2bdb46403386ed36afbd74790fb441a
4
- data.tar.gz: c4c9a3d19a8179cdaaea574cb0e8a4e20d7eefcc
2
+ SHA256:
3
+ metadata.gz: 308f8f046233821f03d87749c7bbbc5bd99d440b471f526bfffc82e50e187d07
4
+ data.tar.gz: 8e5c1636d1a129af2c21daf33fb10d2397da31b9dafafd8abdf924495c1c6775
5
5
  SHA512:
6
- metadata.gz: f5cbcd59aa71b3f3c94334c2a51fec760d7dfb328c12d7fbc9aaa0919bff768f4c33c6ac56e5e17e1edec7eb46d14b9e0210dddad68543369139b335d9fc2bc6
7
- data.tar.gz: 8c732c2235b78f7cb8cd327002e2f74340f540b24e44f36eeacd608219bfd5033345a7241bd2635c0fa7be508097b993f03c340d6f0184d04878c3aa2efc5ce7
6
+ metadata.gz: 4e7350f33658327c5a11e81835de61b2e68a141e812d335fcddab777ea3c36f3ae90bb36756c14656233106e9514bf3742e0a32d9d5ac1d90a89ab946e4c7878
7
+ data.tar.gz: 82bda34380cb304a6422fea70f0af6e14832c71a4c8339407fd192064799725fce1344baae64b915211b28064f8ae89ee1afca7217320ccc443392848c716688
@@ -6,7 +6,7 @@ version: 2
6
6
  jobs:
7
7
  build:
8
8
  docker:
9
- - image: circleci/ruby:2.4.4
9
+ - image: circleci/ruby:2.6.2
10
10
 
11
11
  steps:
12
12
  - checkout
@@ -21,6 +21,7 @@ jobs:
21
21
  - run:
22
22
  name: install dependencies
23
23
  command: |
24
+ gem install bundler -v 2.0.2
24
25
  bundle install --jobs=4 --retry=3 --path vendor/bundle
25
26
 
26
27
  - save_cache:
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
13
  .env
14
+ .byebug_history
@@ -1,5 +1,5 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.4.4
5
- before_install: gem install bundler -v 1.14.6
4
+ - 2.6.2
5
+ before_install: gem install bundler -v 2.0.2
data/README.md CHANGED
@@ -83,50 +83,56 @@ You can find your profiles by making the following Blurb call.
83
83
 
84
84
  This will return a JSON payload of profile information for your account. You can then select the profile ID you want to use.
85
85
 
86
- ## Blurb Values Setup
87
- Before using the Blurb API wrapper you need to set your API values. Simply do that by initializing the Blurb values to your API values.
88
- If you are using Rails, see below.
89
86
 
90
- ```ruby
91
- Blurb.profile_id = "<YOUR_PROFILE_ID>"
92
- Blurb.client_id = "<YOUR_CLIENT_ID>"
93
- Blurb.client_secret = "<YOUR_CLIENT_SECRET>"
94
- Blurb.refresh_token = "<YOUR_REFRESH_TOKEN>"
95
- ```
87
+
88
+
96
89
 
97
90
  ## Rails Integration
98
91
 
99
- You can setup the Amazon API keys and tokens in an initializer script.
100
- Create a file called config/initializers/blurb.rb and setup the following values
92
+ When creating a new resource object, you may pass in a hash containing your api keys and tokens. Utilizing this approach allows you to dynamically toggle accounts and or regions with you application.
101
93
 
102
94
  ```ruby
103
- Blurb.profile_id = "<YOUR_PROFILE_ID>"
104
- Blurb.client_id = "<YOUR_CLIENT_ID>"
105
- Blurb.client_secret = "<YOUR_CLIENT_SECRET>"
106
- Blurb.refresh_token = "<YOUR_REFRESH_TOKEN>"
95
+ authorization_hash = {
96
+ client_id: 'my_client_id',
97
+ profile_id: 'my_profile_id',
98
+ client_secret: 'client_secret',
99
+ refresh_token: 'refresh_token',
100
+ region: 'my_region'
101
+ }
102
+
103
+ blurb_instance = Blurb::Keyword.new(authorization_hash)
107
104
  ```
108
105
 
109
- If you don't want to store your API values in your code which gets checked into a public repo, you can utilize ENV variables
106
+
107
+
108
+
109
+
110
+ If you only plan on using Blurb for one api account and region you can setup the Amazon API keys and tokens in an initializer script.
111
+ Create a file called config/initializers/blurb.rb and setup the following values
110
112
 
111
113
  ```ruby
112
114
  Blurb.profile_id = ENV["YOUR_PROFILE_ID_VAR"]
113
115
  Blurb.client_id = ENV["YOUR_CLIENT_ID_VAR"]
114
116
  Blurb.client_secret = ENV["YOUR_CLIENT_SECRET_VAR"]
115
117
  Blurb.refresh_token = ENV["YOUR_REFRESH_TOKEN_VAR"]
118
+ Blurb.region = ENV["YOUR_REGION_VAR"]
116
119
  ```
117
120
 
118
- You could also store API values in a persistence store and initialize from there too.
119
-
120
- ## API Environments
121
-
122
- By default Blurb will run API calls to the Amazon Advertising API production environment.
123
- If you are under development and want to test out the API to see what it can do, you can set
124
- the following Blurb property to use the API test environment.
121
+ Now, you no longer need to pass in an authorization hash when initializing the resource object.
125
122
 
126
123
  ```ruby
127
- Blurb.test_env = true
124
+ blurb_instance = Blurb::Keyword.new()
128
125
  ```
129
126
 
127
+ ### Valid Region Codes
128
+
129
+ Region Code | Region | Notes
130
+ --- | --- | ---
131
+ TEST | Sandbox Environment | All marketplaces
132
+ NA | North America | Covers US and CA marketplaces
133
+ EU | Europe | Covers UK, FR, IT, ES, and DE marketplaces
134
+ FE | Far East | Cover JP and AU marketplaces
135
+
130
136
  ## Usage
131
137
 
132
138
  All API calls have been setup as closely as possible to REST Resource calls.
@@ -138,19 +144,6 @@ For example, to use the keywords resource object:
138
144
  blurb_instance = Blurb::Keyword.new()
139
145
  ```
140
146
 
141
- Optionally, you may pass in a set of account credentials to override the default API keys and tokens
142
-
143
- ```ruby
144
- authorization_hash = {
145
- client_id: 'my_client_id',
146
- profile_id: 'my_profile_id',
147
- client_secret: 'client_secret',
148
- refresh_token: 'refresh_token'
149
- }
150
-
151
- blurb_instance = Blurb::Keyword.new(authorization_hash)
152
- ```
153
-
154
147
  In calls that require 'campaign_type' as a parameter, you must pass in either 'sp' for sponsored products or 'hsa' for sponsored brands (formerly known as headline search ads).
155
148
 
156
149
  NOTE: Not all API endpoints are currently supported by Blurb. Over time we will get more
@@ -380,6 +373,15 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
380
373
 
381
374
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
382
375
 
376
+ In order to run the rspec test suite, you will need the following variables in a .env file:
377
+
378
+ ```
379
+ PROFILE_ID
380
+ CLIENT_ID
381
+ CLIENT_SECRET
382
+ REFRESH_TOKEN
383
+ ```
384
+
383
385
  ## Contributing
384
386
 
385
387
  Bug reports and pull requests are welcome on GitHub at https://github.com/iserve-products/blurb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
@@ -5,6 +5,7 @@ require "blurb"
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
8
+ require 'dotenv/load'
8
9
 
9
10
  # (If you use this, don't forget to add pry to your Gemfile!)
10
11
  # require "pry"
@@ -1,13 +1,12 @@
1
1
  # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'blurb/version'
5
4
 
6
5
  Gem::Specification.new do |spec|
7
6
  spec.name = "blurb"
8
- spec.version = Blurb::VERSION
9
- spec.authors = ["dlbunker"]
10
- spec.email = ["dan@iserve.com"]
7
+ spec.version = "0.4.0"
8
+ spec.authors = ["dlbunker", "eamigo13"]
9
+ spec.email = ["evan@pattern.com"]
11
10
 
12
11
  spec.summary = %q{Ruby gem for the Amazon Advertising API}
13
12
  spec.description = %q{Amazon released a new Advertising API in 2017. This gem will integrate and allow you to make API calls to Amazon.}
@@ -30,12 +29,16 @@ Gem::Specification.new do |spec|
30
29
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
30
  spec.require_paths = ["lib"]
32
31
 
33
- spec.add_development_dependency "bundler", "~> 1.14"
32
+ spec.add_development_dependency "bundler", "~> 2.0"
34
33
  spec.add_development_dependency "rake", "~> 10.0"
35
34
  spec.add_development_dependency "rspec", "~> 3.0"
36
35
  spec.add_development_dependency "rspec_junit_formatter", "~> 0.3.0"
36
+ spec.add_development_dependency "dotenv"
37
+ spec.add_development_dependency "byebug"
38
+ spec.add_development_dependency "faker", "~> 2.1.0"
37
39
 
38
40
  spec.add_runtime_dependency "rest-client", "~> 2.0"
39
41
  spec.add_runtime_dependency "oauth2", "~> 1.4.0"
42
+ spec.add_runtime_dependency "activesupport"
40
43
 
41
44
  end
@@ -1,32 +1,26 @@
1
- require "oauth2"
2
- require "rest-client"
1
+ require "blurb/account"
2
+ require "blurb/client"
3
3
 
4
- require "blurb/version"
5
- require "blurb/base_resource"
4
+ class Blurb
5
+ attr_accessor :client, :account
6
6
 
7
- require "blurb/bid_recommendation"
8
- require "blurb/campaign"
9
- require "blurb/profile"
10
- require "blurb/report"
11
- require "blurb/snapshot"
12
- require "blurb/suggested_keyword"
13
- require "blurb/keyword"
14
- require "blurb/ad_group"
15
-
16
- module Blurb
17
-
18
- def self.default_account
19
- {
20
- client_secret: self.client_secret,
21
- client_id: self.client_id,
22
- refresh_token: self.refresh_token,
23
- profile_id: self.profile_id,
24
- eu_env: self.eu_env
25
- }
7
+ def initialize(
8
+ # Default to env variables
9
+ client_id: ENV["BLURB_CLIENT_ID"],
10
+ client_secret: ENV["BLURB_CLIENT_SECRET"],
11
+ refresh_token: ENV["BLURB_REFRESH_TOKEN"],
12
+ region: ENV["BLURB_REGION"],
13
+ profile_id: ENV["BLURB_PROFILE_ID"] # profile_id can be left nil
14
+ )
15
+ @client = Client.new(client_id: client_id, client_secret: client_secret)
16
+ @account = Account.new(refresh_token: refresh_token, region: region, client: @client, profile_id: profile_id)
26
17
  end
27
18
 
28
- class << self
29
- attr_accessor :client_secret, :client_id, :refresh_token, :profile_id, :test_env, :eu_env
19
+ def profiles
20
+ @account.profiles
30
21
  end
31
22
 
23
+ def active_profile
24
+ @account.active_profile
25
+ end
32
26
  end
@@ -0,0 +1,108 @@
1
+ require "oauth2"
2
+ require "blurb/client"
3
+ require "blurb/profile"
4
+
5
+ class Blurb
6
+ class Account < BaseClass
7
+ attr_accessor :refresh_token, :api_url, :client, :profiles, :active_profile
8
+
9
+ API_URLS = {
10
+ "TEST" => "https://advertising-api-test.amazon.com",
11
+ "NA" => "https://advertising-api.amazon.com",
12
+ "EU" => "https://advertising-api-eu.amazon.com",
13
+ "FE" => "https://advertising-api-fe.amazon.com"
14
+ }
15
+
16
+ def initialize(refresh_token:, region:, client:, profile_id: nil)
17
+ @refresh_token = refresh_token
18
+ @api_url = API_URLS[region]
19
+ @client = client
20
+ @token_refreshed_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) # current time
21
+ @authorization_token = retrieve_token
22
+ initialize_profiles(profile_id)
23
+ end
24
+
25
+ def initialize_profiles(profile_id=nil)
26
+ @profiles = []
27
+ if profile_id
28
+ @profiles << Profile.new(
29
+ profile_id: profile_id,
30
+ account: self
31
+ )
32
+ else
33
+ amazon_profiles = profile_list()
34
+ amazon_profiles.each do |p|
35
+ @profiles << Profile.new(
36
+ profile_id: p[:profile_id],
37
+ account: self
38
+ )
39
+ end
40
+ end
41
+ @active_profile = @profiles.first
42
+ end
43
+
44
+ def set_active_profile(profile_id)
45
+ @active_profile = get_profile(profile_id)
46
+ end
47
+
48
+ def get_profile(profile_id)
49
+ @profiles.find{ |p| p.profile_id == profile_id }
50
+ end
51
+
52
+ def profile_list
53
+ profile_request("/v2/profiles")
54
+ end
55
+
56
+ def retrieve_profile(profile_id)
57
+ profile_request("/v2/profiles/#{profile_id}")
58
+ end
59
+
60
+ def retrieve_token
61
+ current_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
62
+ elapsed_time = current_time - @token_refreshed_at
63
+
64
+ # refresh the token if it's been over an hour
65
+ if @authorization_token.nil? || elapsed_time >= 3600 # 1 hour #Look at using amazons expires_inblurb/
66
+ response = authorization_client.request(:post, "/auth/o2/token",
67
+ {
68
+ body: {
69
+ grant_type: "refresh_token",
70
+ client_id: @client.client_id,
71
+ refresh_token: @refresh_token,
72
+ client_secret: @client.client_secret
73
+ }
74
+ }
75
+ )
76
+
77
+ @authorization_token = JSON.parse(response.body)['access_token']
78
+ @token_refreshed_at = current_time
79
+ end
80
+
81
+ return @authorization_token
82
+ end
83
+
84
+ private
85
+
86
+ def profile_request(api_path)
87
+ request = Request.new(
88
+ url: "#{@api_url}#{api_path}",
89
+ request_type: :get,
90
+ headers: {
91
+ "Authorization" => "Bearer #{retrieve_token()}",
92
+ "Content-Type" => "application/json",
93
+ "Amazon-Advertising-API-ClientId" => @client.client_id
94
+ }
95
+ )
96
+
97
+ request.make_request
98
+ end
99
+
100
+ def authorization_client
101
+ return OAuth2::Client.new(
102
+ "",
103
+ "",
104
+ :site => "https://api.amazon.com"
105
+ )
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,8 @@
1
+ class Blurb
2
+ class BaseClass
3
+ CAMPAIGN_TYPE_CODES = {
4
+ sp: 'sp',
5
+ sb: 'hsa'
6
+ }.freeze
7
+ end
8
+ end
@@ -0,0 +1,23 @@
1
+ require 'blurb/request_collection_with_campaign_type'
2
+
3
+ class Blurb
4
+ class CampaignRequests < RequestCollectionWithCampaignType
5
+ def create_bulk(create_array)
6
+ create_array = map_campaign_payload(create_array)
7
+ super(create_array)
8
+ end
9
+
10
+ def update_bulk(update_array)
11
+ update_array = map_campaign_payload(update_array)
12
+ super(update_array)
13
+ end
14
+
15
+ private
16
+
17
+ def map_campaign_payload(payload)
18
+ campaign_type_string = "sponsoredProducts" if @campaign_type == CAMPAIGN_TYPE_CODES[:sp]
19
+ campaign_type_string = "sponsoredBrands" if @campaign_type == CAMPAIGN_TYPE_CODES[:sb]
20
+ payload.each{ |p| p[:campaign_type] = campaign_type_string }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ require "blurb/base_class"
2
+
3
+ class Blurb
4
+ class Client < BaseClass
5
+ attr_accessor :client_id, :client_secret
6
+
7
+ def initialize(client_id:, client_secret:)
8
+ @client_id = client_id
9
+ @client_secret = client_secret
10
+ end
11
+ end
12
+ end
@@ -1,12 +1,146 @@
1
- module Blurb
2
- class Profile < BaseResource
1
+ require "blurb/account"
2
+ require "blurb/campaign_requests"
3
+ require "blurb/snapshot_requests"
4
+ require "blurb/report_requests"
5
+ require "blurb/request_collection"
6
+ require "blurb/request_collection_with_campaign_type"
7
+ require "blurb/suggested_keyword_requests"
3
8
 
4
- def list()
5
- profile_request("/v2/profiles")
9
+ class Blurb
10
+ class Profile < BaseClass
11
+
12
+ attr_accessor(
13
+ :account,
14
+ :ad_groups,
15
+ :campaign_negative_keywords,
16
+ :portfolios,
17
+ :product_ads,
18
+ :profile_id,
19
+ :suggested_keywords,
20
+ )
21
+
22
+ def initialize(profile_id:, account:)
23
+ @profile_id = profile_id
24
+ @account = account
25
+
26
+ @sp_campaigns = CampaignRequests.new(
27
+ headers: headers_hash,
28
+ base_url: @account.api_url,
29
+ resource: "campaigns",
30
+ campaign_type: CAMPAIGN_TYPE_CODES[:sp]
31
+ )
32
+ @sb_campaigns = CampaignRequests.new(
33
+ headers: headers_hash,
34
+ base_url: @account.api_url,
35
+ resource: "campaigns",
36
+ campaign_type: CAMPAIGN_TYPE_CODES[:sb]
37
+ )
38
+ @sp_keywords = RequestCollectionWithCampaignType.new(
39
+ headers: headers_hash,
40
+ base_url: @account.api_url,
41
+ resource: "keywords",
42
+ campaign_type: CAMPAIGN_TYPE_CODES[:sp]
43
+ )
44
+ @sb_keywords = RequestCollectionWithCampaignType.new(
45
+ headers: headers_hash,
46
+ base_url: @account.api_url,
47
+ resource: "keywords",
48
+ campaign_type: CAMPAIGN_TYPE_CODES[:sb]
49
+ )
50
+ @sp_snapshots = SnapshotRequests.new(
51
+ headers: headers_hash,
52
+ base_url: @account.api_url,
53
+ campaign_type: CAMPAIGN_TYPE_CODES[:sp]
54
+ )
55
+ @sb_snapshots = SnapshotRequests.new(
56
+ headers: headers_hash,
57
+ base_url: @account.api_url,
58
+ campaign_type: CAMPAIGN_TYPE_CODES[:sb]
59
+ )
60
+ @sp_reports = ReportRequests.new(
61
+ headers: headers_hash,
62
+ base_url: @account.api_url,
63
+ campaign_type: CAMPAIGN_TYPE_CODES[:sp]
64
+ )
65
+ @sb_reports = ReportRequests.new(
66
+ headers: headers_hash,
67
+ base_url: @account.api_url,
68
+ campaign_type: CAMPAIGN_TYPE_CODES[:sb]
69
+ )
70
+ @ad_groups = RequestCollection.new(
71
+ headers: headers_hash,
72
+ base_url: "#{@account.api_url}/v2/sp/adGroups"
73
+ )
74
+ @product_ads = RequestCollection.new(
75
+ headers: headers_hash,
76
+ base_url: "#{account.api_url}/v2/sp/productAds"
77
+ )
78
+ @sp_negative_keywords = RequestCollectionWithCampaignType.new(
79
+ headers: headers_hash,
80
+ base_url: @account.api_url,
81
+ resource: 'negativeKeywords',
82
+ campaign_type: CAMPAIGN_TYPE_CODES[:sp]
83
+ )
84
+ @sb_negative_keywords = RequestCollectionWithCampaignType.new(
85
+ headers: headers_hash,
86
+ base_url: @account.api_url,
87
+ resource: 'negativeKeywords',
88
+ campaign_type: CAMPAIGN_TYPE_CODES[:sb]
89
+ )
90
+ @campaign_negative_keywords = RequestCollection.new(
91
+ headers: headers_hash,
92
+ base_url: "#{@account.api_url}/v2/sp/campaignNegativeKeywords"
93
+ )
94
+ @portfolios = RequestCollection.new(
95
+ headers: headers_hash,
96
+ base_url: "#{@account.api_url}/v2/portfolios"
97
+ )
98
+ @suggested_keywords = SuggestedKeywordRequests.new(
99
+ headers: headers_hash,
100
+ base_url: "#{@account.api_url}/v2/sp"
101
+ )
102
+ end
103
+
104
+ def campaigns(campaign_type)
105
+ return @sp_campaigns if campaign_type == :sp
106
+ return @sb_campaigns if campaign_type == :sb || campaign_type == :hsa
107
+ end
108
+
109
+ def keywords(campaign_type)
110
+ return @sp_keywords if campaign_type == :sp
111
+ return @sb_keywords if campaign_type == :sb || campaign_type == :hsa
112
+ end
113
+
114
+ def negative_keywords(campaign_type)
115
+ return @sp_negative_keywords if campaign_type == :sp
116
+ return @sb_negative_keywords if campaign_type == :sb || campaign_type == :hsa
6
117
  end
7
118
 
8
- def retrieve(profile_id)
9
- profile_request("/v2/profiles/#{profile_id}")
119
+ def snapshots(campaign_type)
120
+ return @sp_snapshots if campaign_type == :sp
121
+ return @sb_snapshots if campaign_type == :sb || campaign_type == :hsa
122
+ end
123
+
124
+ def reports(campaign_type)
125
+ return @sp_reports if campaign_type == :sp
126
+ return @sb_reports if campaign_type == :sb || campaign_type == :hsa
127
+ end
128
+
129
+ def profile_details
130
+ @account.retrieve_profile(@profile_id)
131
+ end
132
+
133
+ def headers_hash(opts = {})
134
+ headers_hash = {
135
+ "Authorization" => "Bearer #{@account.retrieve_token()}",
136
+ "Content-Type" => "application/json",
137
+ "Amazon-Advertising-API-Scope" => @profile_id,
138
+ "Amazon-Advertising-API-ClientId" => @account.client.client_id
139
+ }
140
+
141
+ headers_hash["Content-Encoding"] = "gzip" if opts[:gzip]
142
+
143
+ return headers_hash
10
144
  end
11
145
  end
12
146
  end