google-adwords-api 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/COPYING +0 -0
- data/ChangeLog +4 -0
- data/README.md +9 -236
- data/lib/adwords_api.rb +2 -234
- metadata +8 -134
- data/adwords_api.yml +0 -53
- data/lib/adwords_api/api_config.rb +0 -221
- data/lib/adwords_api/batch_job_utils.rb +0 -334
- data/lib/adwords_api/credential_handler.rb +0 -96
- data/lib/adwords_api/errors.rb +0 -110
- data/lib/adwords_api/incremental_upload_helper.rb +0 -75
- data/lib/adwords_api/query_utils/query_builder.rb +0 -41
- data/lib/adwords_api/query_utils/report_query.rb +0 -30
- data/lib/adwords_api/query_utils/report_query_builder.rb +0 -82
- data/lib/adwords_api/query_utils/service_query.rb +0 -62
- data/lib/adwords_api/query_utils/service_query_builder.rb +0 -83
- data/lib/adwords_api/query_utils/where_builder.rb +0 -97
- data/lib/adwords_api/report_header_handler.rb +0 -80
- data/lib/adwords_api/report_stream.rb +0 -70
- data/lib/adwords_api/report_utils.rb +0 -383
- data/lib/adwords_api/utils.rb +0 -56
- data/lib/adwords_api/utils_reporter.rb +0 -58
- data/lib/adwords_api/v201809/account_label_service.rb +0 -46
- data/lib/adwords_api/v201809/account_label_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/ad_customizer_feed_service.rb +0 -46
- data/lib/adwords_api/v201809/ad_customizer_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/ad_group_ad_service.rb +0 -62
- data/lib/adwords_api/v201809/ad_group_ad_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/ad_group_bid_modifier_service.rb +0 -54
- data/lib/adwords_api/v201809/ad_group_bid_modifier_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/ad_group_criterion_service.rb +0 -62
- data/lib/adwords_api/v201809/ad_group_criterion_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/ad_group_extension_setting_service.rb +0 -54
- data/lib/adwords_api/v201809/ad_group_extension_setting_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/ad_group_feed_service.rb +0 -54
- data/lib/adwords_api/v201809/ad_group_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/ad_group_service.rb +0 -62
- data/lib/adwords_api/v201809/ad_group_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/ad_param_service.rb +0 -46
- data/lib/adwords_api/v201809/ad_param_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/ad_service.rb +0 -46
- data/lib/adwords_api/v201809/ad_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/adwords_user_list_service.rb +0 -62
- data/lib/adwords_api/v201809/adwords_user_list_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/asset_service.rb +0 -46
- data/lib/adwords_api/v201809/asset_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/batch_job_service.rb +0 -54
- data/lib/adwords_api/v201809/batch_job_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/bidding_strategy_service.rb +0 -54
- data/lib/adwords_api/v201809/bidding_strategy_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/budget_order_service.rb +0 -54
- data/lib/adwords_api/v201809/budget_order_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/budget_service.rb +0 -54
- data/lib/adwords_api/v201809/budget_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/campaign_bid_modifier_service.rb +0 -54
- data/lib/adwords_api/v201809/campaign_bid_modifier_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/campaign_criterion_service.rb +0 -54
- data/lib/adwords_api/v201809/campaign_criterion_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/campaign_extension_setting_service.rb +0 -54
- data/lib/adwords_api/v201809/campaign_extension_setting_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/campaign_feed_service.rb +0 -54
- data/lib/adwords_api/v201809/campaign_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/campaign_group_performance_target_service.rb +0 -46
- data/lib/adwords_api/v201809/campaign_group_performance_target_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/campaign_group_service.rb +0 -46
- data/lib/adwords_api/v201809/campaign_group_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/campaign_service.rb +0 -62
- data/lib/adwords_api/v201809/campaign_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/campaign_shared_set_service.rb +0 -54
- data/lib/adwords_api/v201809/campaign_shared_set_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/constant_data_service.rb +0 -110
- data/lib/adwords_api/v201809/constant_data_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/conversion_tracker_service.rb +0 -54
- data/lib/adwords_api/v201809/conversion_tracker_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/custom_affinity_service.rb +0 -62
- data/lib/adwords_api/v201809/custom_affinity_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/customer_extension_setting_service.rb +0 -54
- data/lib/adwords_api/v201809/customer_extension_setting_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/customer_feed_service.rb +0 -54
- data/lib/adwords_api/v201809/customer_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/customer_negative_criterion_service.rb +0 -54
- data/lib/adwords_api/v201809/customer_negative_criterion_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/customer_service.rb +0 -62
- data/lib/adwords_api/v201809/customer_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/customer_sync_service.rb +0 -38
- data/lib/adwords_api/v201809/customer_sync_service_registry.rb +0 -47
- data/lib/adwords_api/v201809/data_service.rb +0 -94
- data/lib/adwords_api/v201809/data_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/draft_async_error_service.rb +0 -46
- data/lib/adwords_api/v201809/draft_async_error_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/draft_service.rb +0 -54
- data/lib/adwords_api/v201809/draft_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/feed_item_service.rb +0 -54
- data/lib/adwords_api/v201809/feed_item_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/feed_item_target_service.rb +0 -54
- data/lib/adwords_api/v201809/feed_item_target_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/feed_mapping_service.rb +0 -54
- data/lib/adwords_api/v201809/feed_mapping_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/feed_service.rb +0 -54
- data/lib/adwords_api/v201809/feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/label_service.rb +0 -54
- data/lib/adwords_api/v201809/label_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/location_criterion_service.rb +0 -46
- data/lib/adwords_api/v201809/location_criterion_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/managed_customer_service.rb +0 -78
- data/lib/adwords_api/v201809/managed_customer_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/media_service.rb +0 -54
- data/lib/adwords_api/v201809/media_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/offline_call_conversion_feed_service.rb +0 -38
- data/lib/adwords_api/v201809/offline_call_conversion_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/offline_conversion_adjustment_feed_service.rb +0 -38
- data/lib/adwords_api/v201809/offline_conversion_adjustment_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/offline_conversion_feed_service.rb +0 -38
- data/lib/adwords_api/v201809/offline_conversion_feed_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/offline_data_upload_service.rb +0 -46
- data/lib/adwords_api/v201809/offline_data_upload_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/report_definition_service.rb +0 -38
- data/lib/adwords_api/v201809/report_definition_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/shared_criterion_service.rb +0 -54
- data/lib/adwords_api/v201809/shared_criterion_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/shared_set_service.rb +0 -54
- data/lib/adwords_api/v201809/shared_set_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/targeting_idea_service.rb +0 -38
- data/lib/adwords_api/v201809/targeting_idea_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/traffic_estimator_service.rb +0 -38
- data/lib/adwords_api/v201809/traffic_estimator_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/trial_async_error_service.rb +0 -46
- data/lib/adwords_api/v201809/trial_async_error_service_registry.rb +0 -46
- data/lib/adwords_api/v201809/trial_service.rb +0 -54
- data/lib/adwords_api/v201809/trial_service_registry.rb +0 -46
- data/lib/adwords_api/version.rb +0 -24
@@ -1,334 +0,0 @@
|
|
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 utility methods specific to using the BatchJobService.
|
19
|
-
|
20
|
-
require 'nokogiri'
|
21
|
-
require 'nori'
|
22
|
-
|
23
|
-
require 'ads_common/http'
|
24
|
-
require 'ads_common/savon_service'
|
25
|
-
require 'adwords_api/errors'
|
26
|
-
require 'adwords_api/incremental_upload_helper'
|
27
|
-
|
28
|
-
module AdwordsApi
|
29
|
-
class BatchJobUtils
|
30
|
-
# Default constructor.
|
31
|
-
#
|
32
|
-
# Args:
|
33
|
-
# - api: AdwordsApi object
|
34
|
-
# - version: API version to use
|
35
|
-
#
|
36
|
-
def initialize(api, version)
|
37
|
-
@api, @version = api, version
|
38
|
-
end
|
39
|
-
|
40
|
-
# Uploads the given operations for a batch job to the provided URL.
|
41
|
-
#
|
42
|
-
# Args:
|
43
|
-
# - hash_operations: An array of ruby has operations to execute by
|
44
|
-
# posting them to the provided URL
|
45
|
-
# - service_name: The name of the AdwordsApi service as a symbol that would
|
46
|
-
# normally make this request
|
47
|
-
# - batch_job_url: The UploadURL provided by BatchJobService
|
48
|
-
#
|
49
|
-
# Raises:
|
50
|
-
# - InvalidBatchJobOperationError: If there is a problem converting the
|
51
|
-
# given operations to SOAP.
|
52
|
-
#
|
53
|
-
def upload_operations(operations, batch_job_url)
|
54
|
-
helper = start_incremental_upload(batch_job_url)
|
55
|
-
helper.upload(operations, true)
|
56
|
-
end
|
57
|
-
|
58
|
-
# Provides a helper to manage incremental uploads.
|
59
|
-
#
|
60
|
-
# Args:
|
61
|
-
# - batch_job_url: The UploadURL provided by BatchJobService for new jobs,
|
62
|
-
# or the upload_url from IncrementalUploadHelper for continued jobs.
|
63
|
-
# - uploaded_bytes: The number of bytes already uploaded for this
|
64
|
-
# incremental batch job. Can be retrieved from the IncrementalUploadHelper
|
65
|
-
# using uploaded_bytes.
|
66
|
-
#
|
67
|
-
# Returns:
|
68
|
-
# - an IncrementalUploadHelper that will accept operations and put them,
|
69
|
-
# keeping track of uploaded bytes automatically.
|
70
|
-
#
|
71
|
-
def start_incremental_upload(batch_job_url, uploaded_bytes = 0)
|
72
|
-
return AdwordsApi::IncrementalUploadHelper.new(
|
73
|
-
self, uploaded_bytes, batch_job_url)
|
74
|
-
end
|
75
|
-
|
76
|
-
# Initializes an upload URL to get the actual URL to which to upload
|
77
|
-
# operations.
|
78
|
-
#
|
79
|
-
# Args:
|
80
|
-
# - batch_job_url: The UploadURL provided by BatchJobService
|
81
|
-
#
|
82
|
-
# Returns:
|
83
|
-
# - The URL that should actually be used to upload operations.
|
84
|
-
#
|
85
|
-
def initialize_url(batch_job_url)
|
86
|
-
headers = DEFAULT_HEADERS
|
87
|
-
headers['Content-Length'] = 0
|
88
|
-
headers['x-goog-resumable'] = 'start'
|
89
|
-
|
90
|
-
response = AdsCommon::Http.post_response(
|
91
|
-
batch_job_url, '', @api.config, headers)
|
92
|
-
|
93
|
-
return response.headers['Location']
|
94
|
-
end
|
95
|
-
|
96
|
-
# Puts the provided operations to the provided URL, allowing
|
97
|
-
# for incremental followup puts.
|
98
|
-
#
|
99
|
-
# Args:
|
100
|
-
# - soap_operations: An array including SOAP operations provided by
|
101
|
-
# generate_soap_operations
|
102
|
-
# - batch_job_url: The UploadURL provided by BatchJobService
|
103
|
-
# - total_content_length: The total number of bytes already uploaded
|
104
|
-
# incrementally. Set this to 0 the first time you call the method.
|
105
|
-
# - is_last_request: Whether or not this set of uploads will conclude the
|
106
|
-
# full request.
|
107
|
-
#
|
108
|
-
# Returns:
|
109
|
-
# - total content length, including what was just uploaded. Pass this back
|
110
|
-
# into this method on subsequent calls.
|
111
|
-
def put_incremental_operations(
|
112
|
-
operations, batch_job_url, total_content_length = 0,
|
113
|
-
is_last_request = false)
|
114
|
-
@api.utils_reporter.batch_job_utils_used()
|
115
|
-
headers = DEFAULT_HEADERS
|
116
|
-
soap_operations = generate_soap_operations(operations)
|
117
|
-
request_body = soap_operations.join
|
118
|
-
is_first_request = (total_content_length == 0)
|
119
|
-
|
120
|
-
if is_first_request
|
121
|
-
request_body = (UPLOAD_XML_PREFIX % [@version]) + request_body
|
122
|
-
end
|
123
|
-
if is_last_request
|
124
|
-
request_body += UPLOAD_XML_SUFFIX
|
125
|
-
end
|
126
|
-
|
127
|
-
request_body = add_padding(request_body)
|
128
|
-
content_length = request_body.bytesize
|
129
|
-
|
130
|
-
headers['Content-Length'] = content_length
|
131
|
-
|
132
|
-
lower_bound = total_content_length
|
133
|
-
upper_bound = total_content_length + content_length - 1
|
134
|
-
total_bytes = is_last_request ? upper_bound + 1 : '*'
|
135
|
-
content_range =
|
136
|
-
"bytes %d-%d/%s" % [lower_bound, upper_bound, total_bytes]
|
137
|
-
|
138
|
-
headers['Content-Range'] = content_range
|
139
|
-
|
140
|
-
log_request(batch_job_url, headers, request_body)
|
141
|
-
|
142
|
-
# The HTTPI library fails to handle the response when uploading
|
143
|
-
# incremental requests. We're not interested in the response, so just
|
144
|
-
# ignore the error.
|
145
|
-
begin
|
146
|
-
AdsCommon::Http.put_response(
|
147
|
-
batch_job_url, request_body, @api.config, headers)
|
148
|
-
rescue ArgumentError
|
149
|
-
end
|
150
|
-
|
151
|
-
total_content_length += content_length
|
152
|
-
return total_content_length
|
153
|
-
end
|
154
|
-
|
155
|
-
# Downloads the results of a batch job from the specified URL.
|
156
|
-
#
|
157
|
-
# Args:
|
158
|
-
# - batch_job_url: The URL provided by BatchJobService to fetch the results
|
159
|
-
# from
|
160
|
-
#
|
161
|
-
# Returns:
|
162
|
-
# - the results of the batch job, as a ruby hash, or nil if none yet exist
|
163
|
-
#
|
164
|
-
def get_job_results(batch_job_url)
|
165
|
-
@api.utils_reporter.batch_job_utils_used()
|
166
|
-
xml_response = AdsCommon::Http.get_response(batch_job_url, @api.config)
|
167
|
-
begin
|
168
|
-
return sanitize_result(
|
169
|
-
get_nori().parse(xml_response.body)[:mutate_response][:rval])
|
170
|
-
rescue
|
171
|
-
return nil
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
private
|
176
|
-
|
177
|
-
# For incremental uploads, the size (in bytes) of the body of the request
|
178
|
-
# must be in multiples of 256k.
|
179
|
-
REQUIRED_CONTENT_LENGTH_INCREMENT = 256 * 1024
|
180
|
-
|
181
|
-
UPLOAD_XML_PREFIX = '<?xml version="1.0" encoding="UTF-8"?><ns1:mutate ' +
|
182
|
-
'xmlns:ns1="https://adwords.google.com/api/adwords/cm/%s">'
|
183
|
-
UPLOAD_XML_SUFFIX = '</ns1:mutate>'
|
184
|
-
DEFAULT_HEADERS = {"Content-Type" => "application/xml"}
|
185
|
-
|
186
|
-
SERVICES_BY_OPERATION_TYPE = {
|
187
|
-
'AdGroupAdOperation' => :AdGroupAdService,
|
188
|
-
'AdGroupAdLabelOperation' => :AdGroupAdService,
|
189
|
-
'AdGroupBidModifierOperation' => :AdGroupBidModifierService,
|
190
|
-
'AdGroupCriterionOperation' => :AdGroupCriterionService,
|
191
|
-
'AdGroupCriterionLabelOperation' => :AdGroupCriterionService,
|
192
|
-
'AdGroupExtensionSettingOperation' => :AdGroupExtensionSettingService,
|
193
|
-
'AdGroupOperation' => :AdGroupService,
|
194
|
-
'AdGroupLabelOperation' => :AdGroupService,
|
195
|
-
'BudgetOperation' => :BudgetService,
|
196
|
-
'CampaignCriterionOperation' => :CampaignCriterionService,
|
197
|
-
'CampaignExtensionSettingOperation' => :CampaignExtensionSettingService,
|
198
|
-
'CampaignLabelOperation' => :CampaignService,
|
199
|
-
'CampaignOperation' => :CampaignService,
|
200
|
-
'CampaignSharedSetOperation' => :CampaignSharedSetService,
|
201
|
-
'CustomerExtensionSettingOperation' => :CustomerExtensionSettingService,
|
202
|
-
'FeedItemOperation' => :FeedItemService,
|
203
|
-
'FeedItemTargetOperation' => :FeedItemTargetService,
|
204
|
-
'SharedCriterionOperation' => :SharedCriterionService,
|
205
|
-
'SharedSetOperation' => :SharedSetService
|
206
|
-
}
|
207
|
-
|
208
|
-
METHODS_BY_OPERATION_TYPE = {
|
209
|
-
'AdGroupAdOperation' => 'mutate_to_xml',
|
210
|
-
'AdGroupAdLabelOperation' => 'mutate_label_to_xml',
|
211
|
-
'AdGroupBidModifierOperation' => 'mutate_to_xml',
|
212
|
-
'AdGroupCriterionOperation' => 'mutate_to_xml',
|
213
|
-
'AdGroupCriterionLabelOperation' => 'mutate_label_to_xml',
|
214
|
-
'AdGroupExtensionSettingOperation' => 'mutate_to_xml',
|
215
|
-
'AdGroupOperation' => 'mutate_to_xml',
|
216
|
-
'AdGroupLabelOperation' => 'mutate_label_to_xml',
|
217
|
-
'BudgetOperation' => 'mutate_to_xml',
|
218
|
-
'CampaignCriterionOperation' => 'mutate_to_xml',
|
219
|
-
'CampaignExtensionSettingOperation' => 'mutate_to_xml',
|
220
|
-
'CampaignLabelOperation' => 'mutate_label_to_xml',
|
221
|
-
'CampaignOperation' => 'mutate_to_xml',
|
222
|
-
'CampaignSharedSetOperation' => 'mutate_to_xml',
|
223
|
-
'CustomerExtensionSettingOperation' => 'mutate_to_xml',
|
224
|
-
'FeedItemOperation' => 'mutate_to_xml',
|
225
|
-
'FeedItemTargetOperation' => 'mutate_to_xml',
|
226
|
-
'SharedCriterionOperation' => 'mutate_to_xml',
|
227
|
-
'SharedSetOperation' => 'mutate_to_xml'
|
228
|
-
}
|
229
|
-
|
230
|
-
def generate_soap_operations(hash_operations)
|
231
|
-
unless hash_operations.is_a?(Array)
|
232
|
-
raise AdwordsApi::Errors::InvalidBatchJobOperationError,
|
233
|
-
'Operations must be in an array.'
|
234
|
-
end
|
235
|
-
return hash_operations.map do |operation|
|
236
|
-
operation_type = operation[:xsi_type]
|
237
|
-
if operation_type.nil?
|
238
|
-
raise AdwordsApi::Errors::InvalidBatchJobOperationError,
|
239
|
-
':xsi_type for operations must be defined ' +
|
240
|
-
'explicitly for batch jobs.'
|
241
|
-
end
|
242
|
-
service_name = SERVICES_BY_OPERATION_TYPE[operation_type]
|
243
|
-
if service_name.nil?
|
244
|
-
raise AdwordsApi::Errors::InvalidBatchJobOperationError,
|
245
|
-
'Unknown operation type: %s' % operation_type
|
246
|
-
end
|
247
|
-
method_name = METHODS_BY_OPERATION_TYPE[operation_type]
|
248
|
-
service = @api.service(service_name, @version)
|
249
|
-
full_soap_xml = service.send(method_name, [operation])
|
250
|
-
operation_xml = extract_soap_operations(full_soap_xml)
|
251
|
-
operation_xml
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
# Given a full SOAP xml string, extract just the operations element
|
256
|
-
# from the SOAP body as a string.
|
257
|
-
def extract_soap_operations(full_soap_xml)
|
258
|
-
doc = Nokogiri::XML(full_soap_xml)
|
259
|
-
operations = doc.css('wsdl|operations')
|
260
|
-
operations.attr('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance')
|
261
|
-
operations.each do |element|
|
262
|
-
check_xsi_type(element)
|
263
|
-
end
|
264
|
-
return operations.to_s
|
265
|
-
end
|
266
|
-
|
267
|
-
def check_xsi_type(xml_node)
|
268
|
-
xsi_type = xml_node['xsi:type']
|
269
|
-
unless xsi_type.nil? or xsi_type.start_with?('ns1:')
|
270
|
-
xml_node['xsi:type'] = 'ns1:' + xsi_type
|
271
|
-
end
|
272
|
-
children = xml_node.children
|
273
|
-
unless children.empty?
|
274
|
-
children.each do |element|
|
275
|
-
check_xsi_type(element)
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
# Logs the request on debug level.
|
281
|
-
def log_request(url, headers, body)
|
282
|
-
logger = @api.logger
|
283
|
-
logger.debug("Report request to: '%s'" % url)
|
284
|
-
logger.debug('HTTP headers: [%s]' %
|
285
|
-
(headers.map { |k, v| [k, v].join(': ') }.join(', ')))
|
286
|
-
logger.debug(body)
|
287
|
-
end
|
288
|
-
|
289
|
-
# Removes extraneous XML information from return hash.
|
290
|
-
def sanitize_result(results)
|
291
|
-
if results.is_a?(Array)
|
292
|
-
ret = []
|
293
|
-
results.each do |result|
|
294
|
-
ret << sanitize_result(result)
|
295
|
-
end
|
296
|
-
return ret
|
297
|
-
end
|
298
|
-
|
299
|
-
if results.is_a?(Hash)
|
300
|
-
ret = {}
|
301
|
-
results.each do |k, v|
|
302
|
-
v = sanitize_result(v) if v.is_a?(Hash)
|
303
|
-
ret[k] = v unless k.to_s.start_with?('@')
|
304
|
-
end
|
305
|
-
return ret
|
306
|
-
end
|
307
|
-
|
308
|
-
return results
|
309
|
-
end
|
310
|
-
|
311
|
-
def add_padding(xml)
|
312
|
-
remainder = xml.bytesize % REQUIRED_CONTENT_LENGTH_INCREMENT
|
313
|
-
return xml if remainder == 0
|
314
|
-
bytes_to_add = REQUIRED_CONTENT_LENGTH_INCREMENT - remainder
|
315
|
-
padded_xml = xml + (' ' * bytes_to_add)
|
316
|
-
return padded_xml
|
317
|
-
end
|
318
|
-
|
319
|
-
def get_nori()
|
320
|
-
return @nori if @nori
|
321
|
-
|
322
|
-
nori_options = {
|
323
|
-
:strip_namespaces => true,
|
324
|
-
:convert_tags_to => lambda { |tag| tag.snakecase.to_sym },
|
325
|
-
:empty_tag_value => "",
|
326
|
-
:advanced_typecasting => false
|
327
|
-
}
|
328
|
-
|
329
|
-
@nori = Nori.new(nori_options)
|
330
|
-
|
331
|
-
return @nori
|
332
|
-
end
|
333
|
-
end
|
334
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
# Encoding: utf-8
|
2
|
-
#
|
3
|
-
# Copyright:: Copyright 2010, 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
|
-
# AdWords-specific credential handler.
|
19
|
-
|
20
|
-
require 'ads_common/credential_handler'
|
21
|
-
require 'adwords_api/api_config'
|
22
|
-
|
23
|
-
module AdwordsApi
|
24
|
-
class CredentialHandler < AdsCommon::CredentialHandler
|
25
|
-
# Whether we're making validate-only requests.
|
26
|
-
attr_accessor :validate_only
|
27
|
-
# Whether we're making partial failure requests.
|
28
|
-
attr_accessor :partial_failure
|
29
|
-
|
30
|
-
def initialize(config)
|
31
|
-
super(config)
|
32
|
-
@validate_only = false
|
33
|
-
@partial_failure = false
|
34
|
-
end
|
35
|
-
|
36
|
-
# Create the list of credentials to be used by the auth handler for header
|
37
|
-
# generation.
|
38
|
-
def credentials(credentials_override = nil)
|
39
|
-
result = super(credentials_override)
|
40
|
-
validate_headers_for_server(result)
|
41
|
-
|
42
|
-
extra_headers = {
|
43
|
-
'userAgent' => generate_user_agent(),
|
44
|
-
'developerToken' => result[:developer_token]
|
45
|
-
}
|
46
|
-
extra_headers['clientCustomerId'] = result[:client_customer_id] if
|
47
|
-
result[:client_customer_id]
|
48
|
-
extra_headers['validateOnly'] = 'true' if @validate_only
|
49
|
-
extra_headers['partialFailure'] = 'true' if @partial_failure
|
50
|
-
result[:extra_headers] = extra_headers
|
51
|
-
return result
|
52
|
-
end
|
53
|
-
|
54
|
-
# Generates string to use as user agent in headers.
|
55
|
-
def generate_user_agent(extra_ids = [])
|
56
|
-
agent_app = @config.read('authentication.user_agent')
|
57
|
-
if !agent_app.nil? && !agent_app.ascii_only?
|
58
|
-
raise AdwordsApi::Errors::InvalidUserAgentError.new(
|
59
|
-
'User agent contains non-ASCII characters.', agent_app)
|
60
|
-
end
|
61
|
-
extra_ids << ['AwApi-Ruby/%s' % AdwordsApi::ApiConfig::CLIENT_LIB_VERSION]
|
62
|
-
super(extra_ids, agent_app)
|
63
|
-
end
|
64
|
-
|
65
|
-
# Returns the client customer ID specified in the current credentials.
|
66
|
-
def identifier()
|
67
|
-
return credentials[:extra_headers]['clientCustomerId']
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
# Validates that the right credentials are being used for the chosen
|
73
|
-
# environment.
|
74
|
-
#
|
75
|
-
# Raises:
|
76
|
-
# - AdwordsApi::Errors:BadCredentialsError if supplied credentials are not
|
77
|
-
# valid.
|
78
|
-
#
|
79
|
-
def validate_headers_for_server(credentials)
|
80
|
-
client_customer_id = credentials[:client_customer_id]
|
81
|
-
|
82
|
-
if client_customer_id and (!(client_customer_id.is_a?(Integer) or
|
83
|
-
(client_customer_id =~ /^\d+(-\d+-\d+)?$/)))
|
84
|
-
raise AdwordsApi::Errors::BadCredentialsError,
|
85
|
-
'Invalid client customer ID: %s' % client_customer_id.to_s
|
86
|
-
end
|
87
|
-
|
88
|
-
token = credentials[:developer_token]
|
89
|
-
if token.nil? || token.empty?
|
90
|
-
raise AdwordsApi::Errors::BadCredentialsError,
|
91
|
-
'Developer token is missing, check credentials.'
|
92
|
-
end
|
93
|
-
return nil
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
data/lib/adwords_api/errors.rb
DELETED
@@ -1,110 +0,0 @@
|
|
1
|
-
# Encoding: utf-8
|
2
|
-
#
|
3
|
-
# Copyright:: Copyright 2010, 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
|
-
# Specific error handling for the AdWords API.
|
19
|
-
|
20
|
-
require 'ads_common/errors'
|
21
|
-
require 'ads_common/results_extractor'
|
22
|
-
|
23
|
-
module AdwordsApi
|
24
|
-
module Errors
|
25
|
-
|
26
|
-
# This class encapsulates base class for API exceptions. More specific
|
27
|
-
# exceptions are generated based on Service WSDL.
|
28
|
-
class ApiException < AdsCommon::Errors::ApiException
|
29
|
-
attr_reader :array_fields
|
30
|
-
|
31
|
-
def initialize(exception_fault, registry)
|
32
|
-
@array_fields ||= []
|
33
|
-
extractor = AdsCommon::ResultsExtractor.new(registry)
|
34
|
-
exception_type = exception_fault[:application_exception_type]
|
35
|
-
exception_data = (exception_type.nil?) ? exception_fault :
|
36
|
-
extractor.extract_exception_data(exception_fault, exception_type)
|
37
|
-
exception_data.each { |key, value| set_field(key, value) }
|
38
|
-
super(exception_data[:message])
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
# Sets instance's property to a value if it is defined
|
44
|
-
def set_field(field, value)
|
45
|
-
if respond_to?(field)
|
46
|
-
value = arrayize(value) if is_array_field(field)
|
47
|
-
instance_variable_set("@#{field}", value)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Makes sure object is an array
|
52
|
-
def arrayize(object)
|
53
|
-
return [] if object.nil?
|
54
|
-
return object.is_a?(Array) ? object : [object]
|
55
|
-
end
|
56
|
-
|
57
|
-
# Should a field be forced to be an array
|
58
|
-
def is_array_field(field)
|
59
|
-
return @array_fields.include?(field.to_s)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Error for invalid credentials sush as malformed ID.
|
64
|
-
class BadCredentialsError < AdsCommon::Errors::ApiException
|
65
|
-
end
|
66
|
-
|
67
|
-
# Error for malformed report definition.
|
68
|
-
class InvalidReportDefinitionError < AdsCommon::Errors::ApiException
|
69
|
-
end
|
70
|
-
|
71
|
-
# Error for server-side report error.
|
72
|
-
class ReportError < AdsCommon::Errors::ApiException
|
73
|
-
attr_reader :http_code
|
74
|
-
|
75
|
-
def initialize(http_code, message)
|
76
|
-
super(message)
|
77
|
-
@http_code = http_code
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Error for server-side report XML error.
|
82
|
-
class ReportXmlError < ReportError
|
83
|
-
attr_reader :type, :trigger, :field_path
|
84
|
-
|
85
|
-
def initialize(http_code, error_type, error_trigger, error_field_path)
|
86
|
-
message =
|
87
|
-
"HTTP code: %d, error type: '%s', trigger: '%s', field path: '%s'" %
|
88
|
-
[http_code, error_type, error_trigger, error_field_path]
|
89
|
-
super(http_code, message)
|
90
|
-
@type = error_type
|
91
|
-
@trigger = error_trigger
|
92
|
-
@field_path = error_field_path
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Error for use an unsupported operation in a batch job.
|
97
|
-
class InvalidBatchJobOperationError < AdsCommon::Errors::ApiException
|
98
|
-
end
|
99
|
-
|
100
|
-
# Error for using an invalid user agent string.
|
101
|
-
class InvalidUserAgentError < AdsCommon::Errors::Error
|
102
|
-
attr_reader :user_agent
|
103
|
-
|
104
|
-
def initialize(message, user_agent)
|
105
|
-
super(message)
|
106
|
-
@user_agent = user_agent
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
@@ -1,75 +0,0 @@
|
|
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
|
-
if @uploaded_bytes == 0
|
39
|
-
@upload_url = @batch_job_utils.initialize_url(upload_url)
|
40
|
-
else
|
41
|
-
@upload_url = upload_url
|
42
|
-
end
|
43
|
-
@finished = false
|
44
|
-
end
|
45
|
-
|
46
|
-
# Takes an array of operations and puts it to the batch job incrementally.
|
47
|
-
#
|
48
|
-
# Args:
|
49
|
-
# - hash_operations: An array of operations to put, represented in hashes
|
50
|
-
# like you would normally pass to services.
|
51
|
-
# - is_last_request: Whether this request is the last request of the
|
52
|
-
# incremental job.
|
53
|
-
#
|
54
|
-
# Raises:
|
55
|
-
# - InvalidBatchJobOperationError: If this incremental upload is already
|
56
|
-
# finished or if there is an error converting the hash operations to
|
57
|
-
# soap operations.
|
58
|
-
#
|
59
|
-
def upload(operations, is_last_request = false)
|
60
|
-
check_status()
|
61
|
-
@uploaded_bytes = @batch_job_utils.put_incremental_operations(
|
62
|
-
operations, @upload_url, @uploaded_bytes, is_last_request)
|
63
|
-
@finished = true if is_last_request
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def check_status()
|
69
|
-
if @finished
|
70
|
-
raise AdwordsApi::Errors::InvalidBatchJobOperationError,
|
71
|
-
'Cannot put new operations to completed incremental upload.'
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# Encoding: utf-8
|
2
|
-
#
|
3
|
-
# Copyright:: Copyright 2018, 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
|
-
# Base class with common methods used across both report and service queries.
|
19
|
-
|
20
|
-
require 'adwords_api/query_utils/where_builder'
|
21
|
-
|
22
|
-
module AdwordsApi
|
23
|
-
class QueryBuilder
|
24
|
-
def initialize(api)
|
25
|
-
@api = api
|
26
|
-
@where = []
|
27
|
-
end
|
28
|
-
|
29
|
-
def where(field)
|
30
|
-
clause = WhereBuilder.new(field)
|
31
|
-
@where << clause
|
32
|
-
return clause
|
33
|
-
end
|
34
|
-
|
35
|
-
def build_where()
|
36
|
-
return '' if @where.empty?
|
37
|
-
wheres = @where.map {|w| w.awql}
|
38
|
-
return sprintf(' WHERE %s', wheres.join(' AND '))
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# Encoding: utf-8
|
2
|
-
#
|
3
|
-
# Copyright:: Copyright 2018, 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
|
-
# Class to hold a generated AWQL query for reports.
|
19
|
-
|
20
|
-
module AdwordsApi
|
21
|
-
class ReportQuery
|
22
|
-
def initialize(query)
|
23
|
-
@query = query
|
24
|
-
end
|
25
|
-
|
26
|
-
def to_s()
|
27
|
-
return @query
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|