google-adwords-api 0.17.0 → 0.18.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 +5 -13
- data/ChangeLog +5 -0
- data/README.md +3 -3
- data/adwords_api.yml +3 -0
- data/examples/v201509/{campaign_management → advanced_operations}/add_complete_campaigns_using_batch_job.rb +10 -16
- data/examples/v201509/advanced_operations/add_keywords_using_incremental_batch_job.rb +179 -0
- data/examples/v201509/reporting/stream_criteria_report_results.rb +97 -0
- data/lib/adwords_api/api_config.rb +0 -86
- data/lib/adwords_api/batch_job_utils.rb +124 -51
- data/lib/adwords_api/incremental_upload_helper.rb +71 -0
- data/lib/adwords_api/report_header_handler.rb +1 -1
- data/lib/adwords_api/report_stream.rb +64 -0
- data/lib/adwords_api/report_utils.rb +88 -8
- data/lib/adwords_api/version.rb +1 -1
- data/test/adwords_api/test_batch_job_utils.rb +15 -0
- metadata +18 -168
- data/examples/v201502/account_management/create_account.rb +0 -88
- data/examples/v201502/account_management/get_account_changes.rb +0 -139
- data/examples/v201502/account_management/get_account_hierarchy.rb +0 -94
- data/examples/v201502/advanced_operations/add_ad_customizers.rb +0 -184
- data/examples/v201502/advanced_operations/add_ad_group_bid_modifier.rb +0 -101
- data/examples/v201502/advanced_operations/add_click_to_download_ad.rb +0 -133
- data/examples/v201502/advanced_operations/add_text_ad_with_upgraded_urls.rb +0 -134
- data/examples/v201502/advanced_operations/create_and_attach_shared_keyword_set.rb +0 -133
- data/examples/v201502/advanced_operations/find_and_remove_criteria_from_shared_set.rb +0 -166
- data/examples/v201502/advanced_operations/get_ad_group_bid_modifiers.rb +0 -102
- data/examples/v201502/advanced_operations/upload_offline_conversions.rb +0 -113
- data/examples/v201502/advanced_operations/use_shared_bidding_strategy.rb +0 -147
- data/examples/v201502/basic_operations/add_ad_groups.rb +0 -140
- data/examples/v201502/basic_operations/add_campaigns.rb +0 -139
- data/examples/v201502/basic_operations/add_keywords.rb +0 -114
- data/examples/v201502/basic_operations/add_text_ads.rb +0 -109
- data/examples/v201502/basic_operations/get_ad_groups.rb +0 -102
- data/examples/v201502/basic_operations/get_campaigns.rb +0 -97
- data/examples/v201502/basic_operations/get_campaigns_with_awql.rb +0 -89
- data/examples/v201502/basic_operations/get_keywords.rb +0 -108
- data/examples/v201502/basic_operations/get_text_ads.rb +0 -110
- data/examples/v201502/basic_operations/pause_ad.rb +0 -88
- data/examples/v201502/basic_operations/remove_ad.rb +0 -89
- data/examples/v201502/basic_operations/remove_ad_group.rb +0 -85
- data/examples/v201502/basic_operations/remove_campaign.rb +0 -87
- data/examples/v201502/basic_operations/remove_keyword.rb +0 -94
- data/examples/v201502/basic_operations/update_ad_group.rb +0 -85
- data/examples/v201502/basic_operations/update_campaign.rb +0 -86
- data/examples/v201502/basic_operations/update_keyword.rb +0 -106
- data/examples/v201502/campaign_management/add_campaign_labels.rb +0 -82
- data/examples/v201502/campaign_management/add_experiment.rb +0 -162
- data/examples/v201502/campaign_management/add_keywords_in_bulk.rb +0 -153
- data/examples/v201502/campaign_management/get_all_disapproved_ads.rb +0 -97
- data/examples/v201502/campaign_management/get_all_disapproved_ads_with_awql.rb +0 -89
- data/examples/v201502/campaign_management/get_campaigns_by_label.rb +0 -108
- data/examples/v201502/campaign_management/promote_experiment.rb +0 -81
- data/examples/v201502/campaign_management/set_ad_parameters.rb +0 -118
- data/examples/v201502/campaign_management/set_criterion_bid_modifier.rb +0 -104
- data/examples/v201502/campaign_management/validate_text_ad.rb +0 -110
- data/examples/v201502/error_handling/handle_partial_failures.rb +0 -130
- data/examples/v201502/error_handling/handle_policy_violation_error.rb +0 -141
- data/examples/v201502/extensions/add_google_my_business_location_extensions.rb +0 -179
- data/examples/v201502/extensions/add_site_links.rb +0 -164
- data/examples/v201502/extensions/add_site_links_using_feeds.rb +0 -271
- data/examples/v201502/migration/migrate_to_extension_settings.rb +0 -386
- data/examples/v201502/migration/upgrade_ad_url.rb +0 -93
- data/examples/v201502/misc/create_ad_words_session_without_properties_file.rb +0 -92
- data/examples/v201502/misc/get_all_images_and_videos.rb +0 -104
- data/examples/v201502/misc/setup_oauth2.rb +0 -84
- data/examples/v201502/misc/upload_image.rb +0 -93
- data/examples/v201502/misc/use_oauth2_jwt.rb +0 -93
- data/examples/v201502/optimization/estimate_keyword_traffic.rb +0 -146
- data/examples/v201502/optimization/get_keyword_bid_simulations.rb +0 -95
- data/examples/v201502/optimization/get_keyword_ideas.rb +0 -126
- data/examples/v201502/remarketing/add_audience.rb +0 -118
- data/examples/v201502/remarketing/add_conversion_tracker.rb +0 -100
- data/examples/v201502/remarketing/add_rule_based_user_lists.rb +0 -167
- data/examples/v201502/reporting/download_criteria_report.rb +0 -85
- data/examples/v201502/reporting/download_criteria_report_with_awql.rb +0 -84
- data/examples/v201502/reporting/get_report_fields.rb +0 -75
- data/examples/v201502/reporting/parallel_report_download.rb +0 -166
- data/examples/v201502/shopping_campaigns/add_product_partition_tree.rb +0 -267
- data/examples/v201502/shopping_campaigns/add_product_scope.rb +0 -129
- data/examples/v201502/shopping_campaigns/add_shopping_campaign.rb +0 -129
- data/examples/v201502/shopping_campaigns/get_product_category_taxonomy.rb +0 -115
- data/examples/v201502/targeting/add_campaign_targeting_criteria.rb +0 -169
- data/examples/v201502/targeting/add_demographic_targeting_criteria.rb +0 -112
- data/examples/v201502/targeting/get_campaign_targeting_criteria.rb +0 -106
- data/examples/v201502/targeting/get_targetable_languages_and_carriers.rb +0 -89
- data/examples/v201502/targeting/lookup_location.rb +0 -108
- data/lib/adwords_api/v201502/account_label_service.rb +0 -46
- data/lib/adwords_api/v201502/account_label_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/ad_customizer_feed_service.rb +0 -46
- data/lib/adwords_api/v201502/ad_customizer_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/ad_group_ad_service.rb +0 -70
- data/lib/adwords_api/v201502/ad_group_ad_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/ad_group_bid_modifier_service.rb +0 -54
- data/lib/adwords_api/v201502/ad_group_bid_modifier_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/ad_group_criterion_service.rb +0 -62
- data/lib/adwords_api/v201502/ad_group_criterion_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/ad_group_extension_setting_service.rb +0 -54
- data/lib/adwords_api/v201502/ad_group_extension_setting_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/ad_group_feed_service.rb +0 -54
- data/lib/adwords_api/v201502/ad_group_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/ad_group_service.rb +0 -62
- data/lib/adwords_api/v201502/ad_group_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/ad_param_service.rb +0 -46
- data/lib/adwords_api/v201502/ad_param_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/adwords_user_list_service.rb +0 -46
- data/lib/adwords_api/v201502/adwords_user_list_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/bidding_strategy_service.rb +0 -54
- data/lib/adwords_api/v201502/bidding_strategy_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/budget_order_service.rb +0 -54
- data/lib/adwords_api/v201502/budget_order_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/budget_service.rb +0 -54
- data/lib/adwords_api/v201502/budget_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/campaign_criterion_service.rb +0 -54
- data/lib/adwords_api/v201502/campaign_criterion_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/campaign_extension_setting_service.rb +0 -54
- data/lib/adwords_api/v201502/campaign_extension_setting_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/campaign_feed_service.rb +0 -54
- data/lib/adwords_api/v201502/campaign_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/campaign_service.rb +0 -62
- data/lib/adwords_api/v201502/campaign_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/campaign_shared_set_service.rb +0 -46
- data/lib/adwords_api/v201502/campaign_shared_set_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/constant_data_service.rb +0 -102
- data/lib/adwords_api/v201502/constant_data_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/conversion_tracker_service.rb +0 -54
- data/lib/adwords_api/v201502/conversion_tracker_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/customer_extension_setting_service.rb +0 -54
- data/lib/adwords_api/v201502/customer_extension_setting_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/customer_feed_service.rb +0 -54
- data/lib/adwords_api/v201502/customer_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/customer_service.rb +0 -46
- data/lib/adwords_api/v201502/customer_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/customer_sync_service.rb +0 -38
- data/lib/adwords_api/v201502/customer_sync_service_registry.rb +0 -47
- data/lib/adwords_api/v201502/data_service.rb +0 -78
- data/lib/adwords_api/v201502/data_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/experiment_service.rb +0 -46
- data/lib/adwords_api/v201502/experiment_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/feed_item_service.rb +0 -54
- data/lib/adwords_api/v201502/feed_item_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/feed_mapping_service.rb +0 -54
- data/lib/adwords_api/v201502/feed_mapping_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/feed_service.rb +0 -54
- data/lib/adwords_api/v201502/feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/geo_location_service.rb +0 -38
- data/lib/adwords_api/v201502/geo_location_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/label_service.rb +0 -54
- data/lib/adwords_api/v201502/label_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/location_criterion_service.rb +0 -46
- data/lib/adwords_api/v201502/location_criterion_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/managed_customer_service.rb +0 -78
- data/lib/adwords_api/v201502/managed_customer_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/media_service.rb +0 -54
- data/lib/adwords_api/v201502/media_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/mutate_job_service.rb +0 -54
- data/lib/adwords_api/v201502/mutate_job_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/offline_conversion_feed_service.rb +0 -38
- data/lib/adwords_api/v201502/offline_conversion_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/report_definition_service.rb +0 -38
- data/lib/adwords_api/v201502/report_definition_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/shared_criterion_service.rb +0 -46
- data/lib/adwords_api/v201502/shared_criterion_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/shared_set_service.rb +0 -46
- data/lib/adwords_api/v201502/shared_set_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/targeting_idea_service.rb +0 -38
- data/lib/adwords_api/v201502/targeting_idea_service_registry.rb +0 -46
- data/lib/adwords_api/v201502/traffic_estimator_service.rb +0 -38
- data/lib/adwords_api/v201502/traffic_estimator_service_registry.rb +0 -46
- data/test/templates/v201502/basic_operations_get_campaigns.def +0 -116
- data/test/templates/v201502/misc_use_oauth2_service_account.def +0 -131
|
@@ -23,6 +23,7 @@ require 'nori'
|
|
|
23
23
|
require 'ads_common/http'
|
|
24
24
|
require 'ads_common/savon_service'
|
|
25
25
|
require 'adwords_api/errors'
|
|
26
|
+
require 'adwords_api/incremental_upload_helper'
|
|
26
27
|
|
|
27
28
|
module AdwordsApi
|
|
28
29
|
class BatchJobUtils
|
|
@@ -36,73 +37,99 @@ module AdwordsApi
|
|
|
36
37
|
@api, @version = api, version
|
|
37
38
|
end
|
|
38
39
|
|
|
39
|
-
#
|
|
40
|
-
# as a normal request.
|
|
40
|
+
# Uploads the given operations for a batch job to the provided URL.
|
|
41
41
|
#
|
|
42
42
|
# Args:
|
|
43
|
-
# - hash_operations: An array of ruby
|
|
43
|
+
# - hash_operations: An array of ruby has operations to execute by
|
|
44
|
+
# posting them to the provided URL
|
|
44
45
|
# - service_name: The name of the AdwordsApi service as a symbol that would
|
|
45
46
|
# normally make this request
|
|
47
|
+
# - batch_job_url: The URL provided by BatchjobService to post the provided
|
|
48
|
+
# operations to
|
|
49
|
+
#
|
|
50
|
+
# Raises:
|
|
51
|
+
# - InvalidBatchJobOperationError: If there is a problem converting the
|
|
52
|
+
# given operations to SOAP.
|
|
53
|
+
#
|
|
54
|
+
def upload_operations(operations, batch_job_url)
|
|
55
|
+
soap_operations = generate_soap_operations(operations)
|
|
56
|
+
post_soap_operations(soap_operations, batch_job_url)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Provides a helper to manage incremental uploads.
|
|
60
|
+
#
|
|
61
|
+
# Args:
|
|
62
|
+
# - batch_job_url: The URL provided by BatchJobService to put the provided
|
|
63
|
+
# operations to.
|
|
64
|
+
# - uploaded_bytes: The number of bytes already uploaded for this
|
|
65
|
+
# incremental batch job. Can be retrieved from the IncrementalUploadHelper
|
|
66
|
+
# using uploaded_bytes.
|
|
46
67
|
#
|
|
47
68
|
# Returns:
|
|
48
|
-
# -
|
|
69
|
+
# - an IncrementalUploadHelper that will accept operations and put them,
|
|
70
|
+
# keeping track of uploaded bytes automatically.
|
|
49
71
|
#
|
|
50
|
-
def
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
'Operations must be in an array.'
|
|
54
|
-
end
|
|
55
|
-
return hash_operations.map do |operation|
|
|
56
|
-
operation_type = operation[:xsi_type]
|
|
57
|
-
if operation_type.nil?
|
|
58
|
-
raise AdwordsApi::Errors::InvalidBatchJobOperationError,
|
|
59
|
-
':xsi_type for operations must be defined ' +
|
|
60
|
-
'explicitly for batch jobs.'
|
|
61
|
-
end
|
|
62
|
-
service_name = SERVICES_BY_OPERATION_TYPE[operation_type]
|
|
63
|
-
if service_name.nil?
|
|
64
|
-
raise AdwordsApi::Errors::InvalidBatchJobOperationError,
|
|
65
|
-
'Unknown operation type: %s' % operation_type
|
|
66
|
-
end
|
|
67
|
-
method_name = METHODS_BY_OPERATION_TYPE[operation_type]
|
|
68
|
-
service = @api.service(service_name, @version)
|
|
69
|
-
full_soap_xml = service.send(method_name, [operation])
|
|
70
|
-
operation_xml = extract_soap_operations(full_soap_xml)
|
|
71
|
-
operation_xml
|
|
72
|
-
end
|
|
72
|
+
def start_incremental_upload(batch_job_url, uploaded_bytes = 0)
|
|
73
|
+
return AdwordsApi::IncrementalUploadHelper.new(
|
|
74
|
+
self, uploaded_bytes, batch_job_url)
|
|
73
75
|
end
|
|
74
76
|
|
|
75
|
-
#
|
|
77
|
+
# Puts the provided operations to the provided URL, allowing
|
|
78
|
+
# for incremental followup puts.
|
|
76
79
|
#
|
|
77
80
|
# Args:
|
|
78
81
|
# - soap_operations: An array including SOAP operations provided by
|
|
79
82
|
# generate_soap_operations
|
|
80
83
|
# - batch_job_url: The URL provided by BatchJobService to post the provided
|
|
81
84
|
# operations to
|
|
85
|
+
# - total_content_length: The total number of bytes already uploaded
|
|
86
|
+
# incrementally. Set this to 0 the first time you call the method.
|
|
87
|
+
# - is_last_request: Whether or not this set of uploads will conclude the
|
|
88
|
+
# full request.
|
|
82
89
|
#
|
|
83
|
-
|
|
90
|
+
# Returns:
|
|
91
|
+
# - total content length, including what was just uploaded. Pass this back
|
|
92
|
+
# into this method on subsequent calls.
|
|
93
|
+
def put_incremental_operations(
|
|
94
|
+
operations, batch_job_url, total_content_length = 0,
|
|
95
|
+
is_last_request = false)
|
|
84
96
|
headers = DEFAULT_HEADERS
|
|
85
|
-
|
|
97
|
+
soap_operations = generate_soap_operations(operations)
|
|
98
|
+
request_body = soap_operations.join
|
|
99
|
+
is_first_request = (total_content_length == 0)
|
|
100
|
+
|
|
101
|
+
if is_first_request
|
|
102
|
+
request_body = (UPLOAD_XML_PREFIX % [@version]) + request_body
|
|
103
|
+
end
|
|
104
|
+
if is_last_request
|
|
105
|
+
request_body += UPLOAD_XML_SUFFIX
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
request_body = add_padding(request_body)
|
|
109
|
+
content_length = request_body.size
|
|
110
|
+
|
|
111
|
+
headers['Content-Length'] = content_length.to_s
|
|
112
|
+
|
|
113
|
+
lower_bound = total_content_length
|
|
114
|
+
upper_bound = total_content_length + content_length - 1
|
|
115
|
+
total_bytes = is_last_request ? upper_bound + 1 : '*'
|
|
116
|
+
content_range = "bytes %d-%d/%s" %
|
|
117
|
+
[lower_bound, upper_bound, total_bytes]
|
|
118
|
+
headers['Content-Range'] = content_range
|
|
119
|
+
|
|
86
120
|
log_request(batch_job_url, headers, request_body)
|
|
87
|
-
response = AdsCommon::Http.post_response(
|
|
88
|
-
batch_job_url, request_body, @api.config, headers)
|
|
89
|
-
end
|
|
90
121
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
#
|
|
103
|
-
def execute_hash_operations(hash_operations, batch_job_url)
|
|
104
|
-
soap_operations = generate_soap_operations(hash_operations)
|
|
105
|
-
post_soap_operations(soap_operations, batch_job_url)
|
|
122
|
+
# The HTTPI library fails to handle the response when uploading
|
|
123
|
+
# incremental requests. We're not interested in the response, so just
|
|
124
|
+
# ignore the error.
|
|
125
|
+
begin
|
|
126
|
+
AdsCommon::Http.put_response(
|
|
127
|
+
batch_job_url, request_body, @api.config, headers)
|
|
128
|
+
rescue ArgumentError
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
total_content_length += content_length
|
|
132
|
+
return total_content_length
|
|
106
133
|
end
|
|
107
134
|
|
|
108
135
|
# Downloads the results of a batch job from the specified URL.
|
|
@@ -126,9 +153,13 @@ module AdwordsApi
|
|
|
126
153
|
|
|
127
154
|
private
|
|
128
155
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
156
|
+
# For incremental uploads, the size (in bytes) of the body of the request
|
|
157
|
+
# must be in multiples of 256k.
|
|
158
|
+
REQUIRED_CONTENT_LENGTH_INCREMENT = 256 * 1024
|
|
159
|
+
|
|
160
|
+
UPLOAD_XML_PREFIX = '<?xml version="1.0" encoding="UTF-8"?><ns1:mutate ' +
|
|
161
|
+
'xmlns:ns1="https://adwords.google.com/api/adwords/cm/%s">'
|
|
162
|
+
UPLOAD_XML_SUFFIX = '</ns1:mutate>'
|
|
132
163
|
DEFAULT_HEADERS = {"Content-Type" => "application/xml"}
|
|
133
164
|
|
|
134
165
|
SERVICES_BY_OPERATION_TYPE = {
|
|
@@ -161,6 +192,40 @@ module AdwordsApi
|
|
|
161
192
|
'FeedItemOperation' => 'mutate_to_xml'
|
|
162
193
|
}
|
|
163
194
|
|
|
195
|
+
def generate_soap_operations(hash_operations)
|
|
196
|
+
unless hash_operations.is_a?(Array)
|
|
197
|
+
raise AdwordsApi::Errors::InvalidBatchJobOperationError,
|
|
198
|
+
'Operations must be in an array.'
|
|
199
|
+
end
|
|
200
|
+
return hash_operations.map do |operation|
|
|
201
|
+
operation_type = operation[:xsi_type]
|
|
202
|
+
if operation_type.nil?
|
|
203
|
+
raise AdwordsApi::Errors::InvalidBatchJobOperationError,
|
|
204
|
+
':xsi_type for operations must be defined ' +
|
|
205
|
+
'explicitly for batch jobs.'
|
|
206
|
+
end
|
|
207
|
+
service_name = SERVICES_BY_OPERATION_TYPE[operation_type]
|
|
208
|
+
if service_name.nil?
|
|
209
|
+
raise AdwordsApi::Errors::InvalidBatchJobOperationError,
|
|
210
|
+
'Unknown operation type: %s' % operation_type
|
|
211
|
+
end
|
|
212
|
+
method_name = METHODS_BY_OPERATION_TYPE[operation_type]
|
|
213
|
+
service = @api.service(service_name, @version)
|
|
214
|
+
full_soap_xml = service.send(method_name, [operation])
|
|
215
|
+
operation_xml = extract_soap_operations(full_soap_xml)
|
|
216
|
+
operation_xml
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def post_soap_operations(soap_operations, batch_job_url)
|
|
221
|
+
headers = DEFAULT_HEADERS
|
|
222
|
+
request_body = (UPLOAD_XML_PREFIX % [@version]) + soap_operations.join +
|
|
223
|
+
UPLOAD_XML_SUFFIX
|
|
224
|
+
log_request(batch_job_url, headers, request_body)
|
|
225
|
+
response = AdsCommon::Http.post_response(
|
|
226
|
+
batch_job_url, request_body, @api.config, headers)
|
|
227
|
+
end
|
|
228
|
+
|
|
164
229
|
# Given a full SOAP xml string, extract just the operations element
|
|
165
230
|
# from the SOAP body as a string.
|
|
166
231
|
def extract_soap_operations(full_soap_xml)
|
|
@@ -217,6 +282,14 @@ module AdwordsApi
|
|
|
217
282
|
return results
|
|
218
283
|
end
|
|
219
284
|
|
|
285
|
+
def add_padding(xml)
|
|
286
|
+
remainder = xml.size % REQUIRED_CONTENT_LENGTH_INCREMENT
|
|
287
|
+
return xml if remainder == 0
|
|
288
|
+
bytes_to_add = REQUIRED_CONTENT_LENGTH_INCREMENT - remainder
|
|
289
|
+
padded_xml = xml + (' ' * bytes_to_add)
|
|
290
|
+
return padded_xml
|
|
291
|
+
end
|
|
292
|
+
|
|
220
293
|
def get_nori()
|
|
221
294
|
return @nori if @nori
|
|
222
295
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# Copyright:: Copyright 2015, Google Inc. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# License:: Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
14
|
+
# implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#
|
|
18
|
+
# Contains helper methods to allow incremental uploads with the
|
|
19
|
+
# BatchJobService.
|
|
20
|
+
|
|
21
|
+
module AdwordsApi
|
|
22
|
+
class IncrementalUploadHelper
|
|
23
|
+
attr_reader :upload_url, :uploaded_bytes
|
|
24
|
+
|
|
25
|
+
# Default constructor.
|
|
26
|
+
#
|
|
27
|
+
# Args:
|
|
28
|
+
# - batch_job_service: The instance of BatchJobService that is providing
|
|
29
|
+
# this helper
|
|
30
|
+
# - uploaded_bytes: The number of bytes that have already been uploaded
|
|
31
|
+
# as part of this incremental process.
|
|
32
|
+
# - upload_url: The URL that should be used to upload incremental
|
|
33
|
+
# operations for this job.
|
|
34
|
+
#
|
|
35
|
+
def initialize(batch_job_utils, uploaded_bytes, upload_url)
|
|
36
|
+
@batch_job_utils = batch_job_utils
|
|
37
|
+
@uploaded_bytes = uploaded_bytes
|
|
38
|
+
@upload_url = upload_url
|
|
39
|
+
@finished = false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Takes an array of operations and puts it to the batch job incrementally.
|
|
43
|
+
#
|
|
44
|
+
# Args:
|
|
45
|
+
# - hash_operations: An array of operations to put, represented in hashes
|
|
46
|
+
# like you would normally pass to services.
|
|
47
|
+
# - is_last_request: Whether this request is the last request of the
|
|
48
|
+
# incremental job.
|
|
49
|
+
#
|
|
50
|
+
# Raises:
|
|
51
|
+
# - InvalidBatchJobOperationError: If this incremental upload is already
|
|
52
|
+
# finished or if there is an error converting the hash operations to
|
|
53
|
+
# soap operations.
|
|
54
|
+
#
|
|
55
|
+
def upload(operations, is_last_request = false)
|
|
56
|
+
check_status()
|
|
57
|
+
@uploaded_bytes = @batch_job_utils.put_incremental_operations(
|
|
58
|
+
operations, @upload_url, @uploaded_bytes, is_last_request)
|
|
59
|
+
@finished = true if is_last_request
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def check_status()
|
|
65
|
+
if @finished
|
|
66
|
+
raise AdwordsApi::Errors::InvalidBatchJobOperationError,
|
|
67
|
+
'Cannot put new operations to completed incremental upload.'
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -67,7 +67,7 @@ module AdwordsApi
|
|
|
67
67
|
include_zero_impressions_header =
|
|
68
68
|
@config.read('library.include_zero_impressions_header')
|
|
69
69
|
unless include_zero_impressions_header.nil?
|
|
70
|
-
headers['
|
|
70
|
+
headers['includeZeroImpressions'] = include_zero_impressions_header.to_s
|
|
71
71
|
end
|
|
72
72
|
return headers
|
|
73
73
|
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# Copyright:: Copyright 2015, Google Inc. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# License:: Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
14
|
+
# implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#
|
|
18
|
+
# Includes a way to iterate over a report stream by line, rather than in
|
|
19
|
+
# arbitrary chunks.
|
|
20
|
+
|
|
21
|
+
module AdwordsApi
|
|
22
|
+
class ReportStream
|
|
23
|
+
def initialize(report_utils, report_definition, cid = nil, format = nil,
|
|
24
|
+
is_awql = false, &block)
|
|
25
|
+
@report_utils = report_utils
|
|
26
|
+
@report_definition = report_definition
|
|
27
|
+
@format = format
|
|
28
|
+
@cid = cid
|
|
29
|
+
@block = block
|
|
30
|
+
@is_awql = is_awql
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.set_up(report_utils, report_definition, cid = nil, &block)
|
|
34
|
+
return ReportStream.new(report_utils, report_definition, cid, &block)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.set_up_with_awql(
|
|
38
|
+
report_utils, report_query, format, cid = nil, &block)
|
|
39
|
+
return ReportStream.new(
|
|
40
|
+
report_utils, report_query, cid, format, true, &block)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def each_line()
|
|
44
|
+
# Determine which method and arguments to use depending on whether
|
|
45
|
+
# this is an AWQL request or not.
|
|
46
|
+
method = 'download_report_as_stream'
|
|
47
|
+
method += '_with_awql' if @is_awql
|
|
48
|
+
args = [@report_definition]
|
|
49
|
+
args << @format if @is_awql
|
|
50
|
+
args << @cid
|
|
51
|
+
|
|
52
|
+
leftover_data = ''
|
|
53
|
+
@report_utils.send(method, *args) do |batch|
|
|
54
|
+
data_to_process = leftover_data + batch
|
|
55
|
+
lines = data_to_process.split('\n')
|
|
56
|
+
leftover_data = lines.pop
|
|
57
|
+
lines.each do |line|
|
|
58
|
+
@block.call(line)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
@block.call(leftover_data) unless leftover_data.empty?()
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -24,6 +24,7 @@ require 'nori'
|
|
|
24
24
|
require 'ads_common/http'
|
|
25
25
|
require 'adwords_api/errors'
|
|
26
26
|
require 'adwords_api/report_header_handler'
|
|
27
|
+
require 'adwords_api/report_stream'
|
|
27
28
|
|
|
28
29
|
module AdwordsApi
|
|
29
30
|
class ReportUtils
|
|
@@ -76,6 +77,45 @@ module AdwordsApi
|
|
|
76
77
|
return nil
|
|
77
78
|
end
|
|
78
79
|
|
|
80
|
+
# Streams a report as a string to the given block. This method will not do
|
|
81
|
+
# error checking on returned values.
|
|
82
|
+
#
|
|
83
|
+
# Args:
|
|
84
|
+
# - report_definition: definition of the report in XML text or hash
|
|
85
|
+
# - path: path to save report to
|
|
86
|
+
# - cid: optional customer ID to run against
|
|
87
|
+
#
|
|
88
|
+
# Returns:
|
|
89
|
+
# - nil
|
|
90
|
+
#
|
|
91
|
+
# Raises:
|
|
92
|
+
# - AdwordsApi::Errors::InvalidReportDefinitionError if the report
|
|
93
|
+
# definition is invalid
|
|
94
|
+
#
|
|
95
|
+
def download_report_as_stream(report_definition, cid = nil, &block)
|
|
96
|
+
return get_report_response(report_definition, cid, &block)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Returns a helper object that can manage breaking the streamed report
|
|
100
|
+
# results into individual lines.
|
|
101
|
+
#
|
|
102
|
+
# Args:
|
|
103
|
+
# - report_definition: definition of the report in XML text or hash
|
|
104
|
+
# - path: path to save report to
|
|
105
|
+
# - cid: optional customer ID to run against
|
|
106
|
+
#
|
|
107
|
+
# Returns:
|
|
108
|
+
# - ReportStream object initialized to begin streaming.
|
|
109
|
+
#
|
|
110
|
+
# Raises:
|
|
111
|
+
# - AdwordsApi::Errors::InvalidReportDefinitionError if the report
|
|
112
|
+
# definition is invalid
|
|
113
|
+
#
|
|
114
|
+
def get_stream_helper(report_definition, cid = nil, &block)
|
|
115
|
+
return AdwordsApi::ReportStream.set_up(
|
|
116
|
+
self, report_definition, cid, &block)
|
|
117
|
+
end
|
|
118
|
+
|
|
79
119
|
# Downloads and returns a report with AWQL.
|
|
80
120
|
#
|
|
81
121
|
# Args:
|
|
@@ -113,6 +153,38 @@ module AdwordsApi
|
|
|
113
153
|
return nil
|
|
114
154
|
end
|
|
115
155
|
|
|
156
|
+
# Streams a report with AWQL as a string to the given block. This method
|
|
157
|
+
# will not do error checking on returned values.
|
|
158
|
+
#
|
|
159
|
+
# Args:
|
|
160
|
+
# - report_query: query for the report as string
|
|
161
|
+
# - format: format for the report as string
|
|
162
|
+
# - cid: optional customer ID to run report against
|
|
163
|
+
#
|
|
164
|
+
# Returns:
|
|
165
|
+
# - nil
|
|
166
|
+
#
|
|
167
|
+
def download_report_as_stream_with_awql(
|
|
168
|
+
report_query, format, cid = nil, &block)
|
|
169
|
+
return get_report_response_with_awql(report_query, format, cid, &block)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Returns a helper object that can manage breaking the streamed report
|
|
173
|
+
# results into individual lines.
|
|
174
|
+
#
|
|
175
|
+
# Args:
|
|
176
|
+
# - report_query: query for the report as string
|
|
177
|
+
# - format: format for the report as string
|
|
178
|
+
# - cid: optional customer ID to run report against
|
|
179
|
+
#
|
|
180
|
+
# Returns:
|
|
181
|
+
# - ReportStream object initialized to begin streaming.
|
|
182
|
+
#
|
|
183
|
+
def get_stream_helper_with_awql(report_query, format, cid = nil, &block)
|
|
184
|
+
return AdwordsApi::ReportStream.set_up_with_awql(
|
|
185
|
+
self, report_query, format, cid, &block)
|
|
186
|
+
end
|
|
187
|
+
|
|
116
188
|
private
|
|
117
189
|
|
|
118
190
|
# Minimal set of required fields for report definition.
|
|
@@ -131,28 +203,36 @@ module AdwordsApi
|
|
|
131
203
|
}
|
|
132
204
|
|
|
133
205
|
# Send POST request for a report and returns Response object.
|
|
134
|
-
def get_report_response(report_definition, cid)
|
|
206
|
+
def get_report_response(report_definition, cid, &block)
|
|
135
207
|
definition_text = get_report_definition_text(report_definition)
|
|
136
208
|
data = '__rdxml=%s' % CGI.escape(definition_text)
|
|
137
|
-
return make_adhoc_request(data, cid)
|
|
209
|
+
return make_adhoc_request(data, cid, &block)
|
|
138
210
|
end
|
|
139
211
|
|
|
140
212
|
# Send POST request for a report with AWQL and returns Response object.
|
|
141
|
-
def get_report_response_with_awql(report_query, format, cid)
|
|
213
|
+
def get_report_response_with_awql(report_query, format, cid, &block)
|
|
142
214
|
data = '__rdquery=%s&__fmt=%s' %
|
|
143
215
|
[CGI.escape(report_query), CGI.escape(format)]
|
|
144
|
-
return make_adhoc_request(data, cid)
|
|
216
|
+
return make_adhoc_request(data, cid, &block)
|
|
145
217
|
end
|
|
146
218
|
|
|
147
219
|
# Makes request and AdHoc service and returns response.
|
|
148
|
-
def make_adhoc_request(data, cid)
|
|
220
|
+
def make_adhoc_request(data, cid, &block)
|
|
149
221
|
url = @api.api_config.adhoc_report_download_url(
|
|
150
222
|
@api.config.read('service.environment'), @version)
|
|
151
223
|
headers = get_report_request_headers(url, cid)
|
|
152
224
|
log_request(url, headers, data)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
225
|
+
# A given block indicates that we should make a stream request and yield
|
|
226
|
+
# the results, rather than return a full response.
|
|
227
|
+
if block_given?
|
|
228
|
+
AdsCommon::Http.post_stream(url, data, @api.config, headers, &block)
|
|
229
|
+
return nil
|
|
230
|
+
else
|
|
231
|
+
response = AdsCommon::Http.post_response(
|
|
232
|
+
url, data, @api.config, headers)
|
|
233
|
+
check_for_errors(response)
|
|
234
|
+
return response
|
|
235
|
+
end
|
|
156
236
|
end
|
|
157
237
|
|
|
158
238
|
# Converts passed object to XML text. Currently support String (no changes)
|