soapy_bing 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/Gemfile +1 -0
- data/README.md +18 -18
- data/Rakefile +1 -0
- data/lib/soapy_bing.rb +5 -1
- data/lib/soapy_bing/account.rb +1 -0
- data/lib/soapy_bing/accounts.rb +13 -17
- data/lib/soapy_bing/ads.rb +18 -41
- data/lib/soapy_bing/ads/campaign_performance_report.rb +49 -0
- data/lib/soapy_bing/ads/campaigns.rb +106 -0
- data/lib/soapy_bing/ads/parsers/bulk_csv_parser.rb +34 -0
- data/lib/soapy_bing/ads/parsers/report_csv_parser.rb +45 -0
- data/lib/soapy_bing/ads/report.rb +93 -0
- data/lib/soapy_bing/campaign_management.rb +21 -0
- data/lib/soapy_bing/country_codes.rb +17 -0
- data/lib/soapy_bing/country_codes.yml +727 -0
- data/lib/soapy_bing/customer.rb +1 -0
- data/lib/soapy_bing/helpers.rb +1 -1
- data/lib/soapy_bing/helpers/zip_downloader.rb +1 -0
- data/lib/soapy_bing/oauth_credentials.rb +1 -0
- data/lib/soapy_bing/param_guard.rb +1 -0
- data/lib/soapy_bing/service.rb +69 -0
- data/lib/soapy_bing/service_operation.rb +62 -0
- data/lib/soapy_bing/version.rb +2 -1
- data/lib/soapy_bing/wsdl/ad_insight.wsdl +1 -0
- data/lib/soapy_bing/wsdl/bulk.wsdl +1 -0
- data/lib/soapy_bing/wsdl/campaign_management.wsdl +1 -0
- data/lib/soapy_bing/wsdl/customer_billing.wsdl +1 -0
- data/lib/soapy_bing/wsdl/customer_management.wsdl +1 -0
- data/lib/soapy_bing/wsdl/reporting.wsdl +1 -0
- data/lib/tasks/console.rake +1 -0
- data/lib/tasks/coverage.rake +1 -0
- data/lib/tasks/spec.rake +1 -0
- data/lib/tasks/upate_wsdl_files.rake +23 -0
- data/lib/tasks/update_country_codes.rake +24 -0
- data/soapy_bing.gemspec +2 -1
- data/spec/fixtures/ads/campaign_performance_report.csv +37 -0
- data/spec/fixtures/ads/campaign_performance_report.json +170 -0
- data/spec/fixtures/ads/campaigns_by_account_id.csv +7 -0
- data/spec/fixtures/{bulk/campaigns.json → ads/campaigns_by_account_id.json} +496 -240
- data/spec/fixtures/ads/campaigns_by_campaign_ids.csv +5 -0
- data/spec/fixtures/ads/campaigns_by_campaign_ids.json +910 -0
- data/spec/fixtures/vcr_cassettes/SoapyBing_Accounts/_list/returns_a_list_of_SoapyBing_Account_objects.yml +27 -27
- data/spec/fixtures/vcr_cassettes/SoapyBing_Ads/_campaigns/by_account_id/returns_parsed_rows.yml +301 -0
- data/spec/fixtures/vcr_cassettes/SoapyBing_Ads/_campaigns/by_campaign_ids/returns_parsed_rows.yml +300 -0
- data/spec/fixtures/vcr_cassettes/SoapyBing_CampaignManagement/_get_geo_locations/returns_a_list_of_geo_locations_hashes.yml +154 -0
- data/spec/fixtures/vcr_cassettes/campaign_performance_report/with_pending_status.yml +65 -94
- data/spec/fixtures/vcr_cassettes/campaign_performance_report/with_successful_empty_response.yml +511 -0
- data/spec/fixtures/vcr_cassettes/campaign_performance_report/with_successful_response.yml +384 -0
- data/spec/integration/soapy_bing/accounts_spec.rb +1 -0
- data/spec/integration/soapy_bing/ads_campaigns_spec.rb +85 -0
- data/spec/integration/soapy_bing/campaign_management_spec.rb +22 -0
- data/spec/integration/soapy_bing/oauth_credentials_spec.rb +1 -0
- data/spec/simplecov_setup.rb +1 -0
- data/spec/soapy_bing/account_spec.rb +6 -2
- data/spec/soapy_bing/accounts_spec.rb +47 -0
- data/spec/soapy_bing/ads/campaign_performance_report_spec.rb +79 -0
- data/spec/soapy_bing/ads/campaigns_spec.rb +99 -0
- data/spec/soapy_bing/ads/{bulk/parsers/csv_parser_spec.rb → parsers/bulk_csv_parser_spec.rb} +5 -4
- data/spec/soapy_bing/ads/{reports/parsers/csv_parser_spec.rb → parsers/report_csv_parser_spec.rb} +6 -4
- data/spec/soapy_bing/country_codes_spec.rb +39 -0
- data/spec/soapy_bing/helpers/zip_downloader_spec.rb +2 -0
- data/spec/soapy_bing/oauth_credentials_spec.rb +6 -2
- data/spec/soapy_bing/param_guard_spec.rb +2 -0
- data/spec/soapy_bing/service_spec.rb +56 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/dotenv.rb +1 -0
- data/spec/support/vcr.rb +75 -6
- metadata +74 -118
- data/lib/soapy_bing/ads/bulk.rb +0 -3
- data/lib/soapy_bing/ads/bulk/campaigns.rb +0 -65
- data/lib/soapy_bing/ads/bulk/parsers.rb +0 -2
- data/lib/soapy_bing/ads/bulk/parsers/csv_parser.rb +0 -35
- data/lib/soapy_bing/ads/reports.rb +0 -4
- data/lib/soapy_bing/ads/reports/base.rb +0 -74
- data/lib/soapy_bing/ads/reports/campaign_performance_report.rb +0 -24
- data/lib/soapy_bing/ads/reports/parsers.rb +0 -2
- data/lib/soapy_bing/ads/reports/parsers/csv_parser.rb +0 -46
- data/lib/soapy_bing/helpers/class_name.rb +0 -10
- data/lib/soapy_bing/soap.rb +0 -4
- data/lib/soapy_bing/soap/request.rb +0 -10
- data/lib/soapy_bing/soap/request/base.rb +0 -38
- data/lib/soapy_bing/soap/request/download_campaigns_by_account_ids_request.rb +0 -17
- data/lib/soapy_bing/soap/request/get_accounts_info_request.rb +0 -17
- data/lib/soapy_bing/soap/request/get_ad_groups_by_campaign_id_request.rb +0 -17
- data/lib/soapy_bing/soap/request/get_ads_by_ad_group_id_request.rb +0 -17
- data/lib/soapy_bing/soap/request/get_bulk_download_status_request.rb +0 -17
- data/lib/soapy_bing/soap/request/get_targets_by_campaign_ids_request.rb +0 -17
- data/lib/soapy_bing/soap/request/poll_generate_report_request.rb +0 -34
- data/lib/soapy_bing/soap/request/submit_generate_report_request.rb +0 -17
- data/lib/soapy_bing/soap/response.rb +0 -14
- data/lib/soapy_bing/soap/response/base.rb +0 -17
- data/lib/soapy_bing/soap/response/download_campaigns_by_account_ids_response.rb +0 -12
- data/lib/soapy_bing/soap/response/get_accounts_info_response.rb +0 -12
- data/lib/soapy_bing/soap/response/get_ad_groups_by_campaign_id_response.rb +0 -12
- data/lib/soapy_bing/soap/response/get_ads_by_ad_group_id_response.rb +0 -12
- data/lib/soapy_bing/soap/response/get_bulk_download_status_response.rb +0 -17
- data/lib/soapy_bing/soap/response/get_targets_by_campaign_ids_response.rb +0 -12
- data/lib/soapy_bing/soap/response/payload.rb +0 -28
- data/lib/soapy_bing/soap/response/poll_generate_report_response.rb +0 -14
- data/lib/soapy_bing/soap/response/report_status.rb +0 -34
- data/lib/soapy_bing/soap/response/submit_generate_report_response.rb +0 -12
- data/lib/soapy_bing/soap/template_renderer.rb +0 -22
- data/lib/soapy_bing/soap/templates/download_campaigns_by_account_ids.xml.erb +0 -22
- data/lib/soapy_bing/soap/templates/get_accounts_info.xml.erb +0 -12
- data/lib/soapy_bing/soap/templates/get_ad_groups_by_campaign_id.xml.erb +0 -15
- data/lib/soapy_bing/soap/templates/get_ads_by_ad_group_id.xml.erb +0 -15
- data/lib/soapy_bing/soap/templates/get_bulk_download_status.xml.erb +0 -15
- data/lib/soapy_bing/soap/templates/get_targets_by_campaign_ids.xml.erb +0 -20
- data/lib/soapy_bing/soap/templates/poll_generate_report.xml.erb +0 -18
- data/lib/soapy_bing/soap/templates/submit_generate_report.xml.erb +0 -46
- data/spec/fixtures/bulk/campaigns.csv +0 -8
- data/spec/fixtures/get_ad_groups_by_campaign_id.json +0 -587
- data/spec/fixtures/get_ads_by_ad_group_id.json +0 -218
- data/spec/fixtures/get_targets_by_campaign_ids.json +0 -81
- data/spec/fixtures/reports/campaign_performance_report.csv +0 -37
- data/spec/fixtures/reports/campaign_performance_report.json +0 -146
- data/spec/fixtures/soap_templates/simple.xml.erb +0 -2
- data/spec/fixtures/vcr_cassettes/SoapyBing_Ads/_get_ad_groups_by_campaign_id/1_1_1.yml +0 -150
- data/spec/fixtures/vcr_cassettes/SoapyBing_Ads/_get_ads_by_ad_group_id/1_2_1.yml +0 -141
- data/spec/fixtures/vcr_cassettes/SoapyBing_Ads/_get_targets_by_campaign_ids/1_3_1.yml +0 -111
- data/spec/fixtures/vcr_cassettes/SoapyBing_Ads_Bulk_Campaigns/_result_file_url/returns_result_file_url.yml +0 -216
- data/spec/fixtures/vcr_cassettes/campaign_performance_report/with_successful_status.yml +0 -284
- data/spec/integration/soapy_bing/ads/bulk/campaigns_spec.rb +0 -35
- data/spec/integration/soapy_bing/ads/reports/campaign_performance_report_spec.rb +0 -40
- data/spec/integration/soapy_bing/ads_spec.rb +0 -32
- data/spec/soapy_bing/ads/reports/campaign_performance_report_spec.rb +0 -42
- data/spec/soapy_bing/ads_spec.rb +0 -33
- data/spec/soapy_bing/helpers/class_name_spec.rb +0 -15
- data/spec/soapy_bing/soap/request/base_spec.rb +0 -55
- data/spec/soapy_bing/soap/request/poll_generate_report_request_spec.rb +0 -60
- data/spec/soapy_bing/soap/response/base_spec.rb +0 -13
- data/spec/soapy_bing/soap/response/get_bulk_download_status_response_spec.rb +0 -60
- data/spec/soapy_bing/soap/response/payload_spec.rb +0 -48
- data/spec/soapy_bing/soap/response/poll_generate_report_response_spec.rb +0 -26
- data/spec/soapy_bing/soap/response/report_status_spec.rb +0 -92
- data/spec/soapy_bing/soap/response/submit_generate_report_response_spec.rb +0 -20
- data/spec/soapy_bing/soap/template_renderer_spec.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6516951a384d76b68b51cbd390f1d66fb7b41f8d
|
4
|
+
data.tar.gz: aa5436b3258ebfda01f6b832782242f0d6c39ee4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4472f06bcc20a6520359a9542d4361e61969214373c40bfbf909d93751de2b7e584d082aa31cadcb94f7dea6fade3d17f03f31d96849117971dd627cd69981b1
|
7
|
+
data.tar.gz: 2c7a31b9d70b3b3c6d82c1532566e456d546b0ef48875773eda984ce80002c1c62bfb8dadea6c54a02176edc0fd99829e04beca9f903461f1ee92287b2e832d3
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.3.
|
1
|
+
2.3.4
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -8,41 +8,41 @@ Client library for [Bing Ads API](https://msdn.microsoft.com/en-us/library/bing-
|
|
8
8
|
In your Gemfile
|
9
9
|
|
10
10
|
```ruby
|
11
|
-
gem 'soapy_bing'
|
11
|
+
gem 'soapy_bing'
|
12
12
|
```
|
13
13
|
|
14
14
|
## Usage Examples
|
15
15
|
|
16
16
|
```ruby
|
17
17
|
bing_ads = SoapyBing::Ads.new
|
18
|
-
|
19
|
-
date_start: '
|
20
|
-
date_end: '
|
21
|
-
|
18
|
+
rows = bing_ads.campaign_performance_report(
|
19
|
+
date_start: '2017-05-14',
|
20
|
+
date_end: '2017-05-14',
|
22
21
|
settings: { # optional
|
23
|
-
columns: [''] # see SoapyBing::
|
22
|
+
columns: [''] # see SoapyBing::Report::Base::DEFAULT_REPORT_SETTINGS[:columns]
|
24
23
|
}
|
25
24
|
)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
25
|
+
# =>
|
26
|
+
# [{
|
27
|
+
# "GregorianDate" => "2017-05-14"
|
28
|
+
# "Hour" => "0",
|
29
|
+
# "CampaignName" => "My Campaign",
|
30
|
+
# "Impressions" => "100",
|
31
|
+
# "Clicks" => "47",
|
32
|
+
# "Spend" => "12.65"
|
33
|
+
# }, {
|
34
|
+
# ...
|
35
|
+
# }]
|
36
36
|
```
|
37
37
|
|
38
38
|
## Authentication
|
39
39
|
|
40
40
|
Authentication attributes could be passed explicitly when new instance of SoapyBing::Ads is created.
|
41
|
-
Or they could be configured as
|
41
|
+
Or they could be configured as Environment variables.
|
42
42
|
|
43
43
|
```ruby
|
44
44
|
SoapyBing::Ads.new(
|
45
|
-
|
45
|
+
oauth_credentials: { # optional, could be configured via environment variables as
|
46
46
|
client_id: '', # ENV['BING_ADS_OAUTH_CLIENT_ID']
|
47
47
|
client_secret: '', # ENV['BING_ADS_OAUTH_CLIENT_SECRET']
|
48
48
|
refresh_token: '' # ENV['BING_ADS_OAUTH_REFRESH_TOKEN']
|
data/Rakefile
CHANGED
data/lib/soapy_bing.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'httparty'
|
3
4
|
require 'retryable'
|
4
5
|
require 'active_support'
|
@@ -9,6 +10,9 @@ require 'soapy_bing/param_guard'
|
|
9
10
|
require 'soapy_bing/customer'
|
10
11
|
require 'soapy_bing/account'
|
11
12
|
require 'soapy_bing/oauth_credentials'
|
12
|
-
require 'soapy_bing/soap'
|
13
13
|
require 'soapy_bing/ads'
|
14
14
|
require 'soapy_bing/accounts'
|
15
|
+
require 'soapy_bing/service'
|
16
|
+
require 'soapy_bing/service_operation'
|
17
|
+
require 'soapy_bing/campaign_management'
|
18
|
+
require 'soapy_bing/country_codes'
|
data/lib/soapy_bing/account.rb
CHANGED
data/lib/soapy_bing/accounts.rb
CHANGED
@@ -1,32 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module SoapyBing
|
3
4
|
class Accounts
|
4
|
-
attr_reader :
|
5
|
+
attr_reader :service
|
5
6
|
|
6
|
-
def initialize(
|
7
|
-
@
|
8
|
-
@customer = Customer.new(customer)
|
7
|
+
def initialize(*args)
|
8
|
+
@service = Service.customer_management(*args)
|
9
9
|
end
|
10
10
|
|
11
11
|
def list
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
customer_id: customer.customer_id,
|
16
|
-
account_id: account['Id']
|
17
|
-
)
|
12
|
+
response = service.get_accounts_info
|
13
|
+
response[:accounts_info][:account_info].map do |account_info|
|
14
|
+
build_account(account_info)
|
18
15
|
end
|
19
16
|
end
|
20
17
|
|
21
18
|
private
|
22
19
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
.payload
|
20
|
+
def build_account(account_info)
|
21
|
+
Account.new(
|
22
|
+
developer_token: service.customer.developer_token,
|
23
|
+
customer_id: service.customer.customer_id,
|
24
|
+
account_id: account_info[:id]
|
25
|
+
)
|
30
26
|
end
|
31
27
|
end
|
32
28
|
end
|
data/lib/soapy_bing/ads.rb
CHANGED
@@ -1,56 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'soapy_bing/ads/
|
2
|
+
|
3
|
+
require 'soapy_bing/ads/campaigns'
|
4
|
+
require 'soapy_bing/ads/campaign_performance_report'
|
4
5
|
|
5
6
|
module SoapyBing
|
6
7
|
class Ads
|
7
|
-
attr_reader :
|
8
|
+
attr_reader :service_options
|
8
9
|
|
9
|
-
def initialize(
|
10
|
-
@
|
11
|
-
@account = Account.new(account)
|
10
|
+
def initialize(service_options = {})
|
11
|
+
@service_options = service_options
|
12
12
|
end
|
13
13
|
|
14
|
-
def campaign_performance_report(date_start:, date_end:, settings: {})
|
15
|
-
|
16
|
-
|
17
|
-
account: account,
|
14
|
+
def campaign_performance_report(date_start:, date_end:, settings: {}, polling_settings: {})
|
15
|
+
CampaignPerformanceReport.new(
|
16
|
+
service_options: service_options,
|
18
17
|
date_start: date_start,
|
19
18
|
date_end: date_end,
|
20
|
-
settings: settings
|
21
|
-
)
|
22
|
-
end
|
23
|
-
|
24
|
-
def bulk_campaigns(entities = nil, polling_settings = {})
|
25
|
-
Bulk::Campaigns.new(
|
26
|
-
oauth_credentials: oauth_credentials,
|
27
|
-
account: account,
|
28
|
-
entities: entities,
|
19
|
+
settings: settings,
|
29
20
|
polling_settings: polling_settings
|
30
|
-
)
|
31
|
-
end
|
32
|
-
|
33
|
-
def get_ad_groups_by_campaign_id(campaign_id)
|
34
|
-
do_request(Soap::Request::GetAdGroupsByCampaignIdRequest, campaign_id: campaign_id)
|
21
|
+
).rows
|
35
22
|
end
|
36
23
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def do_request(klass, options)
|
48
|
-
klass.new(context: {
|
49
|
-
account: account,
|
50
|
-
authentication_token: oauth_credentials.access_token
|
51
|
-
}.merge(options))
|
52
|
-
.perform
|
53
|
-
.payload
|
24
|
+
def campaigns(entities = Campaigns::DEFAULT_ENTITIES, polling_settings: {}, campaign_ids: nil)
|
25
|
+
Campaigns.new(
|
26
|
+
service_options: service_options,
|
27
|
+
entities: entities,
|
28
|
+
polling_settings: polling_settings,
|
29
|
+
campaign_ids: campaign_ids
|
30
|
+
).rows
|
54
31
|
end
|
55
32
|
end
|
56
33
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'soapy_bing/ads/report'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
module SoapyBing
|
7
|
+
class Ads
|
8
|
+
class CampaignPerformanceReport < Report
|
9
|
+
attr_reader :date_start, :date_end
|
10
|
+
|
11
|
+
def initialize(options)
|
12
|
+
super
|
13
|
+
@date_start = Date.parse(options.fetch(:date_start))
|
14
|
+
@date_end = Date.parse(options.fetch(:date_end))
|
15
|
+
end
|
16
|
+
|
17
|
+
def message
|
18
|
+
{
|
19
|
+
aggregation: settings.aggregation,
|
20
|
+
columns: { campaign_performance_report_column: settings.columns },
|
21
|
+
scope: scope,
|
22
|
+
time: {
|
23
|
+
custom_date_range_end: date_hash(date_end),
|
24
|
+
custom_date_range_start: date_hash(date_start)
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def scope
|
32
|
+
{
|
33
|
+
account_ids: {
|
34
|
+
'@xmlns:a1' => 'http://schemas.microsoft.com/2003/10/Serialization/Arrays',
|
35
|
+
'a1:long' => service.account.account_id
|
36
|
+
}
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def date_hash(date)
|
41
|
+
{ day: date.day, month: date.month, year: date.year }
|
42
|
+
end
|
43
|
+
|
44
|
+
def request_type
|
45
|
+
'CampaignPerformanceReportRequest'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'soapy_bing/ads/parsers/bulk_csv_parser'
|
4
|
+
|
5
|
+
module SoapyBing
|
6
|
+
class Ads
|
7
|
+
class Campaigns
|
8
|
+
DEFAULT_ENTITIES = %w[CampaignTargetCriterions Ads].freeze
|
9
|
+
DEFAULT_POLLING_SETTINGS = {
|
10
|
+
tries: 20,
|
11
|
+
sleep: ->(n) { n < 7 ? 2**n : 120 }
|
12
|
+
}.freeze
|
13
|
+
NotCompleted = Class.new(StandardError)
|
14
|
+
StatusFailed = Class.new(StandardError)
|
15
|
+
|
16
|
+
attr_reader :service, :entities, :polling_settings, :status, :campaign_ids
|
17
|
+
|
18
|
+
def initialize(
|
19
|
+
service_options:,
|
20
|
+
entities: DEFAULT_ENTITIES,
|
21
|
+
polling_settings: {},
|
22
|
+
campaign_ids: nil
|
23
|
+
)
|
24
|
+
@service = Service.bulk(service_options)
|
25
|
+
@entities = entities
|
26
|
+
@polling_settings = DEFAULT_POLLING_SETTINGS.merge(polling_settings)
|
27
|
+
@campaign_ids = campaign_ids
|
28
|
+
end
|
29
|
+
|
30
|
+
def rows
|
31
|
+
@rows ||= Parsers::BulkCsvParser.new(Helpers::ZipDownloader.new(result_file_url).read).rows
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def result_file_url
|
37
|
+
@result_file_url ||= begin
|
38
|
+
wait_status_complete
|
39
|
+
status[:result_file_url]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def fetch_status
|
44
|
+
response = service.get_bulk_download_status(request_id: download_request_id)
|
45
|
+
if response[:request_status] == 'Failed'
|
46
|
+
raise StatusFailed, response[:errors].to_s
|
47
|
+
end
|
48
|
+
@status = response.slice(:percent_complete, :request_status, :result_file_url)
|
49
|
+
end
|
50
|
+
|
51
|
+
def wait_status_complete
|
52
|
+
Retryable.retryable(polling_settings.merge(on: NotCompleted)) do
|
53
|
+
fetch_status
|
54
|
+
raise NotCompleted if status[:request_status] != 'Completed'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def download_request_id
|
59
|
+
@download_request_id ||= download_campaigns
|
60
|
+
end
|
61
|
+
|
62
|
+
def download_campaigns
|
63
|
+
response = campaign_ids ? by_campaign_ids : by_account_ids
|
64
|
+
response[:download_request_id]
|
65
|
+
end
|
66
|
+
|
67
|
+
def by_campaign_ids
|
68
|
+
service.download_campaigns_by_campaign_ids(
|
69
|
+
{
|
70
|
+
campaigns: {
|
71
|
+
campaign_scope: campaign_scope
|
72
|
+
}
|
73
|
+
}.merge(common_request_body)
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
def campaign_scope
|
78
|
+
campaign_ids.map do |campaign_id|
|
79
|
+
{
|
80
|
+
campaign_id: campaign_id,
|
81
|
+
parent_account_id: service.account.account_id
|
82
|
+
}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def by_account_ids
|
87
|
+
service.download_campaigns_by_account_ids(
|
88
|
+
{
|
89
|
+
account_ids: {
|
90
|
+
'@xmlns:a1' => 'http://schemas.microsoft.com/2003/10/Serialization/Arrays',
|
91
|
+
'a1:long' => service.account.account_id
|
92
|
+
}
|
93
|
+
}.merge(common_request_body)
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
def common_request_body
|
98
|
+
{
|
99
|
+
download_entities: { download_entity: entities },
|
100
|
+
download_file_type: 'Csv',
|
101
|
+
format_version: '5.0'
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'csv'
|
4
|
+
|
5
|
+
module SoapyBing
|
6
|
+
class Ads
|
7
|
+
module Parsers
|
8
|
+
class BulkCsvParser
|
9
|
+
def initialize(raw)
|
10
|
+
@raw = raw
|
11
|
+
end
|
12
|
+
|
13
|
+
def rows
|
14
|
+
@rows ||= begin
|
15
|
+
header, *body = extract_csv_payload
|
16
|
+
body.map { |row| header.zip(row).to_h }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :raw
|
23
|
+
|
24
|
+
def extract_csv_payload
|
25
|
+
text = raw.dup
|
26
|
+
text.force_encoding(Encoding::UTF_8).encode! unless text.encoding == Encoding::UTF_8
|
27
|
+
text.sub!(/^\xEF\xBB\xBF/, '') # cleanup BOM
|
28
|
+
|
29
|
+
CSV.parse(text)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'csv'
|
4
|
+
|
5
|
+
module SoapyBing
|
6
|
+
class Ads
|
7
|
+
module Parsers
|
8
|
+
class ReportCsvParser
|
9
|
+
class FormatError < StandardError; end
|
10
|
+
|
11
|
+
CSV_PAYLOAD_OFFSET_FRONT = 10 # First 10 csv lines are report metadata
|
12
|
+
CSV_PAYLOAD_OFFSET_BACK = 2 # Last 2 csv lines are Microsoft copyright
|
13
|
+
|
14
|
+
def initialize(raw)
|
15
|
+
@raw = raw
|
16
|
+
end
|
17
|
+
|
18
|
+
def rows
|
19
|
+
@rows ||= begin
|
20
|
+
header, *body = extract_csv_payload
|
21
|
+
raise FormatError if body.size != payload_rows_number
|
22
|
+
body.map { |row| header.zip(row).to_h }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :raw
|
29
|
+
|
30
|
+
def extract_csv_payload
|
31
|
+
text = raw.dup
|
32
|
+
text.force_encoding(Encoding::UTF_8).encode! unless text.encoding == Encoding::UTF_8
|
33
|
+
text.sub!(/^\xEF\xBB\xBF/, '') # cleanup BOM
|
34
|
+
|
35
|
+
csv_rows = CSV.parse(text)
|
36
|
+
csv_rows[CSV_PAYLOAD_OFFSET_FRONT...-CSV_PAYLOAD_OFFSET_BACK]
|
37
|
+
end
|
38
|
+
|
39
|
+
def payload_rows_number
|
40
|
+
raw.match(/"Rows: (\d+)"/)[1].to_i
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|