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.
@@ -1,48 +1,52 @@
1
- module Blurb
2
- class Report < BaseResource
3
- CAMPAIGNS = "campaigns"
4
- AD_GROUPS = "adGroups"
5
- KEYWORDS = "keywords"
6
- PRODUCT_ADS = "productAds"
7
- ASINS = "asins"
8
- TARGETS = "targets"
1
+ require 'blurb/request_collection_with_campaign_type'
9
2
 
10
- def create(params = {}, opts = {})
11
- # required argument checks
12
- raise ArgumentError.new("params hash must contain a recordType") unless params["recordType"]
13
-
14
- # If no metrics are passed in, use the default metrics
15
- metrics = params["metrics"] || get_default_metrics(params["recordType"],params["campaignType"])
3
+ class Blurb
4
+ class ReportRequests < RequestCollectionWithCampaignType
5
+ def initialize(campaign_type:, base_url:, headers:)
6
+ @campaign_type = campaign_type
7
+ @base_url = "#{base_url}/v2/#{@campaign_type}"
8
+ @headers = headers
9
+ end
16
10
 
17
- api_params = {
18
- "reportDate" => params["reportDate"],
19
- "metrics" => metrics
11
+ def create(
12
+ record_type:,
13
+ report_date: Date.today,
14
+ metrics: nil,
15
+ segment: nil
16
+ )
17
+ # create payload
18
+ metrics = get_default_metrics(record_type.to_s.underscore.to_sym) if metrics.nil?
19
+ payload = {
20
+ metrics: metrics.map{ |m| m.to_s.camelize(:lower) }.join(","),
21
+ report_date: report_date
20
22
  }
23
+ payload[:segment] = segment if segment
21
24
 
22
- api_params["segment"] = params["segment"] if params["segment"]
23
-
24
- if params["recordType"] == ASINS
25
- request_url = "/v2/#{ASINS}/report"
26
- api_params["campaignType"] = 'sponsoredProducts' if params["campaignType"] == SPONSORED_PRODUCTS
27
- raise ArgumentError.new("ASIN report is not supported for Sponsored Brands") if params["campaignType"] == SPONSORED_BRANDS
28
- else
29
- request_url = "/v2/#{params["campaignType"]}/#{params["recordType"]}/report"
30
- end
31
-
32
- post_request(request_url, api_params)
25
+ execute_request(
26
+ api_path: "/#{record_type.to_s.camelize(:lower)}/report",
27
+ request_type: :post,
28
+ payload: payload
29
+ )
33
30
  end
34
31
 
35
- def status(report_id, opts = {})
36
- get_request("/v2/reports/#{report_id}")
32
+ def retrieve(report_id)
33
+ execute_request(
34
+ api_path: "/reports/#{report_id}",
35
+ request_type: :get,
36
+ )
37
37
  end
38
38
 
39
- def download(location, opts = {})
40
- opts.merge!({:full_path => true, :gzip => true, :no_token => true})
41
- get_request(location, opts)
39
+ def download(report_id)
40
+ execute_request(
41
+ api_path: "/reports/#{report_id}/download",
42
+ request_type: :get,
43
+ )
42
44
  end
43
45
 
44
- def get_default_metrics(record_type, campaign_type)
45
- if campaign_type == SPONSORED_BRANDS
46
+ private
47
+
48
+ def get_default_metrics(record_type)
49
+ if @campaign_type == CAMPAIGN_TYPE_CODES[:sb]
46
50
  return [
47
51
  "campaignId",
48
52
  "impressions",
@@ -52,7 +56,7 @@ module Blurb
52
56
  "attributedSales14dSameSKU",
53
57
  "attributedConversions14d",
54
58
  "attributedConversions14dSameSKU"
55
- ].join(",") if record_type == CAMPAIGNS
59
+ ] if record_type == :campaigns
56
60
  return [
57
61
  "adGroupId",
58
62
  "campaignId",
@@ -63,7 +67,7 @@ module Blurb
63
67
  "attributedSales14dSameSKU",
64
68
  "attributedConversions14d",
65
69
  "attributedConversions14dSameSKU"
66
- ].join(",") if record_type == AD_GROUPS
70
+ ] if record_type == :ad_groups
67
71
  return [
68
72
  "keywordId",
69
73
  "adGroupId",
@@ -74,27 +78,9 @@ module Blurb
74
78
  "attributedSales14d",
75
79
  "attributedSales14dSameSKU",
76
80
  "attributedConversions14d",
77
- "attributedConversions14dSameSKU"
78
- ].join(",") if record_type == KEYWORDS
79
- elsif campaign_type == SPONSORED_PRODUCTS
80
- return [
81
- "campaignName",
82
- "campaignId",
83
- "adGroupId",
84
- "adGroupName",
85
- "asin",
86
- "otherAsin",
87
- "sku",
88
- "currency",
89
- "attributedUnitsOrdered1dOtherSKU",
90
- "attributedUnitsOrdered7dOtherSKU",
91
- "attributedUnitsOrdered14dOtherSKU",
92
- "attributedUnitsOrdered30dOtherSKU",
93
- "attributedSales1dOtherSKU",
94
- "attributedSales7dOtherSKU",
95
- "attributedSales14dOtherSKU",
96
- "attributedSales30dOtherSKU"
97
- ].join(",") if record_type == ASINS
81
+ "attributedConversions14dSameSKU"
82
+ ] if record_type == :keywords
83
+ elsif @campaign_type == CAMPAIGN_TYPE_CODES[:sp]
98
84
  return [
99
85
  "campaignName",
100
86
  "campaignId",
@@ -123,7 +109,7 @@ module Blurb
123
109
  "attributedSales7dSameSKU",
124
110
  "attributedSales14dSameSKU",
125
111
  "attributedSales30dSameSKU"
126
- ].join(",") if record_type == CAMPAIGNS
112
+ ] if record_type == :campaigns
127
113
  return [
128
114
  "campaignName",
129
115
  "campaignId",
@@ -152,7 +138,7 @@ module Blurb
152
138
  "attributedSales7dSameSKU",
153
139
  "attributedSales14dSameSKU",
154
140
  "attributedSales30dSameSKU"
155
- ].join(",") if record_type == AD_GROUPS
141
+ ] if record_type == :ad_groups
156
142
  return [
157
143
  "campaignName",
158
144
  "campaignId",
@@ -182,7 +168,7 @@ module Blurb
182
168
  "attributedSales7dSameSKU",
183
169
  "attributedSales14dSameSKU",
184
170
  "attributedSales30dSameSKU"
185
- ].join(",") if record_type == KEYWORDS
171
+ ] if record_type == :keywords
186
172
  return [
187
173
  "campaignName",
188
174
  "campaignId",
@@ -214,7 +200,7 @@ module Blurb
214
200
  "attributedSales7dSameSKU",
215
201
  "attributedSales14dSameSKU",
216
202
  "attributedSales30dSameSKU"
217
- ].join(",") if record_type == PRODUCT_ADS
203
+ ] if record_type == :product_ads
218
204
  return [
219
205
  "campaignName",
220
206
  "campaignId",
@@ -245,7 +231,7 @@ module Blurb
245
231
  "attributedSales7dSameSKU",
246
232
  "attributedSales14dSameSKU",
247
233
  "attributedSales30dSameSKU"
248
- ].join(",") if record_type == TARGETS
234
+ ] if record_type == :targets
249
235
  return [
250
236
  "campaignName",
251
237
  "campaignId",
@@ -277,7 +263,7 @@ module Blurb
277
263
  "attributedSales7dSameSKU",
278
264
  "attributedSales14dSameSKU",
279
265
  "attributedSales30dSameSKU"
280
- ].join(",") if record_type == PORTFOLIOS
266
+ ] if record_type == :portfolios
281
267
  end
282
268
  end
283
269
  end
@@ -0,0 +1,81 @@
1
+ require 'active_support/core_ext/string'
2
+ require "rest-client"
3
+ require "blurb/base_class"
4
+
5
+ class Blurb
6
+ class Request < BaseClass
7
+
8
+ def initialize(url:, request_type:, payload: nil, headers:, url_params: nil)
9
+ @url = setup_url(url, url_params)
10
+ @payload = convert_payload(payload)
11
+ @headers = headers
12
+ @request_type = request_type
13
+ end
14
+
15
+ def request_config
16
+ request_config = {
17
+ method: @request_type,
18
+ url: @url,
19
+ headers: @headers
20
+ }
21
+
22
+ case @request_type
23
+ when :get
24
+ request_config[:max_redirects] = 0
25
+ when :post, :put
26
+ request_config[:payload] = @payload if @payload
27
+ end
28
+
29
+ return request_config
30
+ end
31
+
32
+ def make_request
33
+ begin
34
+ resp = RestClient::Request.execute(request_config())
35
+ rescue RestClient::ExceptionWithResponse => err
36
+ # If this happens, then we are downloading a report from the api, so we can simply download the location
37
+ if err.response.code == 307
38
+ return RestClient.get(err.response.headers[:location])
39
+ else
40
+ return JSON.parse(err.response.body)
41
+ end
42
+ end
43
+ resp = convert_response(resp)
44
+ return resp
45
+ end
46
+
47
+ private
48
+ def setup_url(url, url_params)
49
+ url += "?#{URI.encode_www_form(camelcase_keys(url_params))}" if url_params
50
+ return url
51
+ end
52
+
53
+ def convert_payload(payload)
54
+ return if payload.nil?
55
+ payload = payload.map{|r| camelcase_keys(r)} if payload.class == Array
56
+ payload = camelcase_keys(payload) if payload.class == Hash
57
+ return payload.to_json
58
+ end
59
+
60
+ def convert_response(resp)
61
+ resp = JSON.parse(resp)
62
+ resp = resp.map{|r| underscore_keys(r)} if resp.class == Array
63
+ resp = underscore_keys(resp) if resp.class == Hash
64
+ #TODO convert to symbols recursively
65
+ return resp
66
+ end
67
+
68
+ def camelcase_keys(hash)
69
+ map = hash.map do |key,value|
70
+ value = value.strftime('%Y%m%d') if value.class == Date || value.class == Time
71
+ [key.to_s.camelize(:lower), value]
72
+ end
73
+ map.to_h
74
+ end
75
+
76
+ def underscore_keys(hash)
77
+ hash.map{|k,v| [k.underscore.to_sym, v]}.to_h
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,99 @@
1
+ require 'blurb/request'
2
+ require "blurb/base_class"
3
+
4
+ class Blurb
5
+ class RequestCollection < BaseClass
6
+
7
+ def initialize(headers:, base_url:)
8
+ @base_url = base_url
9
+ @headers = headers
10
+ end
11
+
12
+ def list(url_params=nil)
13
+ execute_request(
14
+ request_type: :get,
15
+ url_params: url_params
16
+ )
17
+ end
18
+
19
+ def list_extended(url_params=nil)
20
+ execute_request(
21
+ api_path: "/extended",
22
+ request_type: :get,
23
+ url_params: url_params
24
+ )
25
+ end
26
+
27
+ def retrieve(resource_id)
28
+ execute_request(
29
+ api_path: "/#{resource_id}",
30
+ request_type: :get
31
+ )
32
+ end
33
+
34
+ def retrieve_extended(resource_id)
35
+ execute_request(
36
+ api_path: "/extended/#{resource_id}",
37
+ request_type: :get
38
+ )
39
+ end
40
+
41
+ def create(**create_params)
42
+ create_bulk([create_params])
43
+ end
44
+
45
+ def create_bulk(create_array)
46
+ execute_bulk_request(
47
+ request_type: :post,
48
+ payload: create_array,
49
+ api_limit: 100
50
+ )
51
+ end
52
+
53
+ def update(**update_params)
54
+ update_bulk([update_params])
55
+ end
56
+
57
+ def update_bulk(update_array)
58
+ execute_bulk_request(
59
+ request_type: :put,
60
+ payload: update_array,
61
+ api_limit: 100
62
+ )
63
+ end
64
+
65
+ def delete(resource_id)
66
+ execute_request(
67
+ api_path: "/#{resource_id}",
68
+ request_type: :delete
69
+ )
70
+ end
71
+
72
+ private
73
+
74
+ def execute_request(api_path: "", request_type:, payload: nil, url_params: nil)
75
+ url = "#{@base_url}#{api_path}"
76
+
77
+ request = Request.new(
78
+ url: url,
79
+ url_params: url_params,
80
+ request_type: request_type,
81
+ payload: payload,
82
+ headers: @headers
83
+ )
84
+
85
+ request.make_request
86
+ end
87
+
88
+ # Split up bulk requests to match the api limit
89
+ def execute_bulk_request(api_limit:, **execute_request_params)
90
+ results = []
91
+ payloads = execute_request_params[:payload].each_slice(api_limit).to_a
92
+ payloads.each do |p|
93
+ execute_request_params[:payload] = p
94
+ results << execute_request(execute_request_params)
95
+ end
96
+ results.flatten
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,12 @@
1
+ require 'blurb/request_collection'
2
+
3
+ class Blurb
4
+ class RequestCollectionWithCampaignType < RequestCollection
5
+
6
+ def initialize(campaign_type:, resource:, base_url:, headers:)
7
+ @campaign_type = campaign_type
8
+ @base_url = "#{base_url}/v2/#{@campaign_type}/#{resource}"
9
+ @headers = headers
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ require 'blurb/request_collection_with_campaign_type'
2
+
3
+ class Blurb
4
+ class SnapshotRequests < RequestCollectionWithCampaignType
5
+ def initialize(campaign_type:, base_url:, headers:)
6
+ @campaign_type = campaign_type
7
+ @base_url = "#{base_url}/v2/#{@campaign_type}"
8
+ @headers = headers
9
+ end
10
+
11
+ def create(record_type, state_filter='enabled,paused')
12
+ execute_request(
13
+ api_path: "/#{record_type.to_s.camelize(:lower)}/snapshot",
14
+ request_type: :post,
15
+ payload: {state_filter: state_filter}
16
+ )
17
+ end
18
+
19
+ def retrieve(snapshot_id)
20
+ execute_request(
21
+ api_path: "/snapshots/#{snapshot_id}",
22
+ request_type: :get,
23
+ )
24
+ end
25
+
26
+ def download(snapshot_id)
27
+ download_url = retrieve(snapshot_id)[:location]
28
+ headers = @headers.dup["Content-Encoding"] = "gzip"
29
+ Request.new(
30
+ url: download_url,
31
+ request_type: :get,
32
+ headers: @headers
33
+ ).make_request
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,61 @@
1
+ require 'blurb/request'
2
+
3
+ class Blurb
4
+ class SuggestedKeywordRequests
5
+ def initialize(base_url:, headers:)
6
+ @base_url = base_url
7
+ @headers = headers
8
+ end
9
+
10
+ def ad_group_retrieve(ad_group_id)
11
+ execute_request(
12
+ api_path: "/adGroups/#{ad_group_id}/suggested/keywords",
13
+ request_type: :get
14
+ )
15
+ end
16
+
17
+ def ad_group_retrieve_extended(ad_group_id)
18
+ execute_request(
19
+ api_path: "/adGroups/#{ad_group_id}/suggested/keywords/extended",
20
+ request_type: :get
21
+ )
22
+ end
23
+
24
+ def asin_retrieve(asin_value, max_num_suggestions=100)
25
+ url_params = {max_num_suggestions: max_num_suggestions}
26
+ execute_request(
27
+ api_path: "/asins/#{asin_value}/suggested/keywords",
28
+ request_type: :get,
29
+ url_params: url_params
30
+ )
31
+ end
32
+
33
+ def asin_list(asin_list, max_num_suggestions=100)
34
+ url_params = {max_num_suggestions: max_num_suggestions}
35
+ execute_request(
36
+ api_path: '/asins/suggested/keywords',
37
+ request_type: :post,
38
+ payload: {
39
+ asins: asin_list,
40
+ max_num_suggestions: max_num_suggestions
41
+ }
42
+ )
43
+ end
44
+
45
+ private
46
+
47
+ def execute_request(api_path: "", request_type:, payload: nil, url_params: nil)
48
+ url = "#{@base_url}#{api_path}"
49
+
50
+ request = Request.new(
51
+ url: url,
52
+ url_params: url_params,
53
+ request_type: request_type,
54
+ payload: payload,
55
+ headers: @headers
56
+ )
57
+
58
+ request.make_request
59
+ end
60
+ end
61
+ end