bing_ads_api 0.0.5
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.
- data/README.md +57 -0
- data/lib/ads_common_for_bing_ads.rb +49 -0
- data/lib/ads_common_for_bing_ads/api_config.rb +41 -0
- data/lib/ads_common_for_bing_ads/auth/client_login_handler.rb +168 -0
- data/lib/ads_common_for_bing_ads/build/savon_registry.rb +15 -0
- data/lib/ads_common_for_bing_ads/parameters_validator.rb +36 -0
- data/lib/ads_common_for_bing_ads/savon_headers_base_header_handler.rb +9 -0
- data/lib/ads_common_for_bing_ads/savon_service.rb +141 -0
- data/lib/bing_ads_api.rb +175 -0
- data/lib/bing_ads_api/api_config.rb +162 -0
- data/lib/bing_ads_api/client_login_header_handler.rb +21 -0
- data/lib/bing_ads_api/credential_handler.rb +91 -0
- data/lib/bing_ads_api/errors.rb +564 -0
- data/lib/bing_ads_api/report_header_handler.rb +46 -0
- data/lib/bing_ads_api/report_utils.rb +202 -0
- data/lib/bing_ads_api/v7/administration_service.rb +37 -0
- data/lib/bing_ads_api/v7/administration_service_registry.rb +30 -0
- data/lib/bing_ads_api/v7/campaign_management_service.rb +398 -0
- data/lib/bing_ads_api/v7/campaign_management_service_registry.rb +30 -0
- data/lib/bing_ads_api/v7/customer_billing_service.rb +58 -0
- data/lib/bing_ads_api/v7/customer_billing_service_registry.rb +30 -0
- data/lib/bing_ads_api/v7/customer_management_service.rb +98 -0
- data/lib/bing_ads_api/v7/customer_management_service_registry.rb +30 -0
- data/lib/bing_ads_api/v7/notification_service.rb +38 -0
- data/lib/bing_ads_api/v7/notification_service_registry.rb +30 -0
- data/lib/bing_ads_api/v7/reporting_service.rb +38 -0
- data/lib/bing_ads_api/v7/reporting_service_registry.rb +30 -0
- data/lib/bing_ads_api/v8/ad_intelligence_service.rb +86 -0
- data/lib/bing_ads_api/v8/ad_intelligence_service_registry.rb +30 -0
- data/lib/bing_ads_api/v8/administration_service.rb +38 -0
- data/lib/bing_ads_api/v8/administration_service_registry.rb +30 -0
- data/lib/bing_ads_api/v8/bulk_service.rb +42 -0
- data/lib/bing_ads_api/v8/bulk_service_registry.rb +30 -0
- data/lib/bing_ads_api/v8/campaign_management_service.rb +390 -0
- data/lib/bing_ads_api/v8/campaign_management_service_registry.rb +30 -0
- data/lib/bing_ads_api/v8/customer_billing_service.rb +62 -0
- data/lib/bing_ads_api/v8/customer_billing_service_registry.rb +30 -0
- data/lib/bing_ads_api/v8/customer_management_service.rb +162 -0
- data/lib/bing_ads_api/v8/customer_management_service_registry.rb +30 -0
- data/lib/bing_ads_api/v8/notification_service.rb +38 -0
- data/lib/bing_ads_api/v8/notification_service_registry.rb +30 -0
- data/lib/bing_ads_api/v8/optimizer_service.rb +46 -0
- data/lib/bing_ads_api/v8/optimizer_service_registry.rb +30 -0
- data/lib/bing_ads_api/v8/reporting_service.rb +38 -0
- data/lib/bing_ads_api/v8/reporting_service_registry.rb +30 -0
- data/lib/bing_ads_api/version.rb +5 -0
- data/rakefile.rb +54 -0
- metadata +156 -0
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
Bing Ads Api Client
|
2
|
+
=============
|
3
|
+
|
4
|
+
Description
|
5
|
+
-------------
|
6
|
+
A simple ruby wrapper for the Bing Ads API based on the gem "google-ads-common".
|
7
|
+
|
8
|
+
Usage
|
9
|
+
-------------
|
10
|
+
|
11
|
+
# install in your gem file
|
12
|
+
gem 'bing_ads_api', :git => 'https://github.com/weboglobin/bing_ads_api.git'
|
13
|
+
|
14
|
+
# initialize the client
|
15
|
+
client = BingAdsApi::Api.new(
|
16
|
+
{
|
17
|
+
:authentication => {
|
18
|
+
:method => 'ClientLogin',
|
19
|
+
:developer_token => 'DEVELOPER_TOKEN',
|
20
|
+
:user_name => 'USERNAME',
|
21
|
+
:password => 'PASSWORD',
|
22
|
+
:customer_id => 'customer_id', # may be optional for some requests
|
23
|
+
:customer_account_id => 'customer_account_id' # may be optional for some requests
|
24
|
+
},
|
25
|
+
:service => {:environment => 'PRODUCTION'},
|
26
|
+
:library => {:log_level => 'DEBUG'}
|
27
|
+
})
|
28
|
+
|
29
|
+
# select the service and the API version (:v7 or :v8)
|
30
|
+
administration_service = client.service(:AdministrationService, :v7)
|
31
|
+
|
32
|
+
# send your request
|
33
|
+
result = administration_service.get_assigned_quota()
|
34
|
+
|
35
|
+
# select another service
|
36
|
+
campaign_service = client.service(:CampaignManagementService, :v7)
|
37
|
+
|
38
|
+
# send another request
|
39
|
+
result = campaign_service.get_campaigns_by_account_id({:account_id => 00000})
|
40
|
+
|
41
|
+
# create a campaign
|
42
|
+
result2 = campaign_service.add_campaigns({:account_id => 00000,
|
43
|
+
:campaigns => {:campaign => [{:budget_type => "DailyBudgetWithMaximumMonthlySpend",
|
44
|
+
:conversion_tracking_enabled => false,
|
45
|
+
:daily_budget => 5,
|
46
|
+
:daylight_saving => false,
|
47
|
+
:description => "A perfect new campaign",
|
48
|
+
:monthly_budget => 50,
|
49
|
+
:name => "perfectcampaign",
|
50
|
+
:time_zone => "BrusselsCopenhagenMadridParis"}]
|
51
|
+
}
|
52
|
+
})
|
53
|
+
|
54
|
+
About the gem
|
55
|
+
-------------
|
56
|
+
The tests still have to be written.
|
57
|
+
Any help is welcome !
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'ads_common/api'
|
2
|
+
require 'ads_common/api_config'
|
3
|
+
require 'ads_common/credential_handler'
|
4
|
+
require 'ads_common/errors'
|
5
|
+
require 'ads_common/http'
|
6
|
+
require 'ads_common/savon_service'
|
7
|
+
require 'ads_common/parameters_validator'
|
8
|
+
require 'ads_common/build/savon_generator'
|
9
|
+
require 'ads_common/build/savon_registry'
|
10
|
+
require 'ads_common/savon_headers/base_header_handler'
|
11
|
+
require 'ads_common/savon_headers/oauth_header_handler'
|
12
|
+
require 'ads_common/savon_headers/httpi_request_proxy'
|
13
|
+
|
14
|
+
####### AdsCommon Overriden for Bing Ads #########
|
15
|
+
module AdsCommonForBingAds
|
16
|
+
class Api < AdsCommon::Api; end
|
17
|
+
module ApiConfig; include AdsCommon::ApiConfig; end
|
18
|
+
class Config < AdsCommon::Config; end
|
19
|
+
class CredentialHandler < AdsCommon::CredentialHandler; end
|
20
|
+
module Errors; include AdsCommon::Errors; end
|
21
|
+
class Http < AdsCommon::Http; end
|
22
|
+
class ParametersValidator < AdsCommon::ParametersValidator; end
|
23
|
+
class ResultsExtractor < AdsCommon::ResultsExtractor; end
|
24
|
+
class SavonService < AdsCommon::SavonService; end
|
25
|
+
module Utils; include AdsCommon::Utils; end
|
26
|
+
module ApiConfig; include AdsCommon::ApiConfig; end
|
27
|
+
# Auth
|
28
|
+
module Auth
|
29
|
+
class BaseHandler < AdsCommon::Auth::BaseHandler; end
|
30
|
+
class ClientLoginHandler < AdsCommon::Auth::ClientLoginHandler; end
|
31
|
+
class OAuth2Handler < AdsCommon::Auth::OAuth2Handler; end
|
32
|
+
class OAuthHandler < AdsCommon::Auth::OAuthHandler; end
|
33
|
+
end
|
34
|
+
# Build
|
35
|
+
module Build
|
36
|
+
class SavonAbstractGenerator < AdsCommon::Build::SavonAbstractGenerator; end
|
37
|
+
class SavonGenerator < AdsCommon::Build::SavonGenerator; end
|
38
|
+
class SavonRegistry < AdsCommon::Build::SavonRegistry; end
|
39
|
+
class SavonRegistryGenerator < AdsCommon::Build::SavonRegistryGenerator; end
|
40
|
+
class SavonServiceGenerator < AdsCommon::Build::SavonServiceGenerator; end
|
41
|
+
end
|
42
|
+
# SavonHeaders
|
43
|
+
module SavonHeaders
|
44
|
+
class BaseHeaderHandler < AdsCommon::SavonHeaders::BaseHeaderHandler; end
|
45
|
+
class OAuthHeaderHandler < AdsCommon::SavonHeaders::OAuthHeaderHandler; end
|
46
|
+
# httpi_request_proxy is ::OAuth::RequestProxy::HTTPIRequest < OAuth::RequestProxy::Base
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
####### Overriden for Bing Ads #########
|
2
|
+
AdsCommonForBingAds::ApiConfig.module_eval do
|
3
|
+
# Get the endpoint for a service on a given environment and API version.
|
4
|
+
#
|
5
|
+
# Args:
|
6
|
+
# - environment: the service environment to be used
|
7
|
+
# - version: the API version
|
8
|
+
# - service: the name of the API service
|
9
|
+
#
|
10
|
+
# Returns:
|
11
|
+
# The endpoint URL
|
12
|
+
#
|
13
|
+
def endpoint(environment, version, service)
|
14
|
+
if !address_config().nil?
|
15
|
+
address_config()[version][service][environment].to_s
|
16
|
+
else
|
17
|
+
""
|
18
|
+
end
|
19
|
+
end
|
20
|
+
# Generates an array of WSDL URLs based on defined Services and version
|
21
|
+
# supplied. This method is used by generators to determine what service
|
22
|
+
# wrappers to generate.
|
23
|
+
#
|
24
|
+
# Args:
|
25
|
+
# - version: the API version.
|
26
|
+
#
|
27
|
+
# Returns
|
28
|
+
# hash of pairs Service => WSDL URL
|
29
|
+
#
|
30
|
+
def get_wsdls(version)
|
31
|
+
res = {}
|
32
|
+
services(version).each do |service|
|
33
|
+
if (!address_config().nil?)
|
34
|
+
path = address_config()[version][service][default_environment()].to_s
|
35
|
+
end
|
36
|
+
res[service.to_s] = path || ""
|
37
|
+
end
|
38
|
+
return res
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
####### Overriden for Bing Ads #########
|
2
|
+
|
3
|
+
AdsCommonForBingAds::Auth::ClientLoginHandler.class_eval do
|
4
|
+
|
5
|
+
#ACCOUNT_TYPE = 'GOOGLE'
|
6
|
+
#AUTH_PATH = '/accounts/ClientLogin'
|
7
|
+
#AUTH_PREFIX = 'GoogleLogin auth='
|
8
|
+
#CAPTCHA_PATH = '/accounts/'
|
9
|
+
|
10
|
+
# Initializes the ClientLoginHandler with all the necessary details.
|
11
|
+
def initialize(config, auth_server, service_name)
|
12
|
+
super(config)
|
13
|
+
@server = auth_server
|
14
|
+
@service_name = service_name
|
15
|
+
end
|
16
|
+
|
17
|
+
# Invalidates the stored token if the user_name, password or provided auth
|
18
|
+
# token have changed.
|
19
|
+
def property_changed(prop, value)
|
20
|
+
if [:user_name, :password].include?(prop)
|
21
|
+
@token = nil
|
22
|
+
end
|
23
|
+
if :auth_token.eql?(prop)
|
24
|
+
@token = create_token_from_string(value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Handle specific ClientLogin errors.
|
29
|
+
def handle_error(error)
|
30
|
+
# TODO: Add support for automatically regenerating auth tokens when they
|
31
|
+
# expire.
|
32
|
+
get_logger().error(error)
|
33
|
+
raise error
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns authorization string.
|
37
|
+
def auth_string(credentials, request)
|
38
|
+
return [AUTH_PREFIX, get_token(credentials)].join
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Auxiliary method to validate the credentials for token generation.
|
44
|
+
#
|
45
|
+
# Args:
|
46
|
+
# - credentials: a hash with the credentials for the account being
|
47
|
+
# accessed
|
48
|
+
#
|
49
|
+
# Raises:
|
50
|
+
# - AdsCommonForBingAds::Errors::AuthError if validation fails
|
51
|
+
#
|
52
|
+
def validate_credentials(credentials)
|
53
|
+
if credentials.nil?
|
54
|
+
raise AdsCommonForBingAds::Errors::AuthError, 'No credentials supplied.'
|
55
|
+
end
|
56
|
+
|
57
|
+
if credentials[:auth_token].nil?
|
58
|
+
if credentials[:user_name].nil?
|
59
|
+
raise AdsCommonForBingAds::Errors::AuthError,
|
60
|
+
'UserName address not included in credentials.'
|
61
|
+
end
|
62
|
+
if credentials[:password].nil?
|
63
|
+
raise AdsCommonForBingAds::Errors::AuthError,
|
64
|
+
'Password not included in credentials.'
|
65
|
+
end
|
66
|
+
else
|
67
|
+
if credentials[:user_name] and credentials[:password]
|
68
|
+
get_logger().warn('Both auth_token and login credentials present' +
|
69
|
+
', preferring auth_token.')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Auxiliary method to generate an authentication token for login in via
|
75
|
+
# the ClientLogin API.
|
76
|
+
#
|
77
|
+
# Args:
|
78
|
+
# - credentials: a hash with the credentials for the account being
|
79
|
+
# accessed
|
80
|
+
#
|
81
|
+
# Returns:
|
82
|
+
# - The auth token for the account
|
83
|
+
#
|
84
|
+
# Raises:
|
85
|
+
# - AdsCommonForBingAds::Errors::AuthError if authentication fails
|
86
|
+
#
|
87
|
+
def create_token(credentials)
|
88
|
+
token = credentials.include?(:auth_token) ?
|
89
|
+
create_token_from_string(credentials[:auth_token]) :
|
90
|
+
generate_token(credentials)
|
91
|
+
return token
|
92
|
+
end
|
93
|
+
|
94
|
+
# Creates token for provided auth string. Trivial for this handler.
|
95
|
+
def create_token_from_string(token_string)
|
96
|
+
return token_string
|
97
|
+
end
|
98
|
+
|
99
|
+
# Prepares POST data for ClientLogin request.
|
100
|
+
def get_login_data(credentials)
|
101
|
+
user_name = CGI.escape(credentials[:user_name])
|
102
|
+
password = CGI.escape(credentials[:password])
|
103
|
+
service_name = @service_name
|
104
|
+
data = "accountType=%s&Email=%s&Passwd=%s&service=%s" %
|
105
|
+
[ACCOUNT_TYPE, user_name, password, service_name]
|
106
|
+
if credentials[:logintoken] and credentials[:logincaptcha]
|
107
|
+
data += "&logintoken=%s&logincaptcha=%s" %
|
108
|
+
[CGI.escape(credentials[:logintoken]),
|
109
|
+
CGI.escape(credentials[:logincaptcha])]
|
110
|
+
end
|
111
|
+
return data
|
112
|
+
end
|
113
|
+
|
114
|
+
# Generates new client login token based on credentials.
|
115
|
+
def generate_token(credentials)
|
116
|
+
validate_credentials(credentials)
|
117
|
+
|
118
|
+
url = @server + AUTH_PATH
|
119
|
+
data = get_login_data(credentials)
|
120
|
+
headers = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
121
|
+
|
122
|
+
response = AdsCommonForBingAds::Http.post_response(url, data, @config, headers)
|
123
|
+
results = parse_token_text(response.body)
|
124
|
+
|
125
|
+
if response.code == 200 and results.include?('Auth')
|
126
|
+
return results['Auth']
|
127
|
+
else
|
128
|
+
handle_login_error(credentials, response, results)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Raises relevant error based on response and parsed results.
|
133
|
+
def handle_login_error(credentials, response, results)
|
134
|
+
# Handling for known errors.
|
135
|
+
if 'CaptchaRequired'.eql?(results['Error'])
|
136
|
+
captcha_url = @server + CAPTCHA_PATH + results['CaptchaUrl']
|
137
|
+
raise AdsCommonForBingAds::Errors::CaptchaRequiredError.new(results['Error'],
|
138
|
+
results['CaptchaToken'], captcha_url, results['Url'])
|
139
|
+
end
|
140
|
+
# For other errors throwing a generic error.
|
141
|
+
error_message = "ClientLogin failed for user_name '%s': HTTP code %d." %
|
142
|
+
[credentials[:user_name], response.code]
|
143
|
+
error_str = results['Error'] || response.body
|
144
|
+
error_message += " Error: %s." % error_str if error_str
|
145
|
+
if results.include?('Info')
|
146
|
+
error_message += " Info: %s." % results['Info']
|
147
|
+
end
|
148
|
+
raise AdsCommonForBingAds::Errors::AuthError.new(error_message, error_str,
|
149
|
+
results['Info'])
|
150
|
+
end
|
151
|
+
|
152
|
+
# Extracts key-value pairs from ClientLogin server response.
|
153
|
+
#
|
154
|
+
# Args:
|
155
|
+
# - text: server response string
|
156
|
+
#
|
157
|
+
# Returns:
|
158
|
+
# Hash of key-value pairs
|
159
|
+
#
|
160
|
+
def parse_token_text(text)
|
161
|
+
return text.split("\n").inject({}) do |result, line|
|
162
|
+
key, *values = line.split('=')
|
163
|
+
result[key] = values.join('=')
|
164
|
+
result
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
class AdsCommonForBingAds::Build::SavonRegistry
|
3
|
+
|
4
|
+
# Extracts input parameters of given method as an array.
|
5
|
+
def extract_input_parameters(op_node, doc)
|
6
|
+
input_element = REXML::XPath.first(op_node, 'descendant::wsdl:input')
|
7
|
+
input_name = get_element_name(input_element)
|
8
|
+
input_fields = find_sequence_fields(input_name, doc)
|
9
|
+
return {:name => input_name.snakecase, :fields => input_fields}
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
AdsCommonForBingAds::ParametersValidator.class_eval do
|
3
|
+
|
4
|
+
# Validates input parameters to:
|
5
|
+
# - add parameter names;
|
6
|
+
# - resolve xsi:type where required;
|
7
|
+
# - convert some native types to XML.
|
8
|
+
def validate_args(action_name, args)
|
9
|
+
in_params = @registry.get_method_signature(action_name)[:input] # Hash like {:name=>"get_accounts_info_request", :fields=>[]}
|
10
|
+
# TODO: compare number of parameters.
|
11
|
+
args_hash = args#{in_params[:name] => deep_copy(args)}
|
12
|
+
#validate_arguments(args_hash, in_params)
|
13
|
+
return args_hash
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Validates given arguments based on provided fields list.
|
19
|
+
def validate_arguments(args_hash, fields_list, type_ns = nil)
|
20
|
+
check_extra_fields(args_hash, array_from_named_list(fields_list))
|
21
|
+
add_order_key(args_hash, fields_list)
|
22
|
+
fields_list.each do |field|
|
23
|
+
key = field[:name]
|
24
|
+
item = args_hash[key]
|
25
|
+
check_required_argument_present(item, field)
|
26
|
+
if item
|
27
|
+
item_type = get_full_type_signature(field[:type])
|
28
|
+
item_ns = field[:ns] || type_ns
|
29
|
+
key = handle_namespace_override(args_hash, key, item_ns) if item_ns
|
30
|
+
validate_arg(item, args_hash, key, item_type)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return args_hash
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
####### Overriden for Bing Ads #########
|
2
|
+
|
3
|
+
class AdsCommonForBingAds::SavonService < AdsCommon::SavonService
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
# [CHANGES:
|
8
|
+
# => ParametersValidator to AdsCommonForBingAds::ParametersValidator
|
9
|
+
# => ResultsExtractor to AdsCommon::ResultsExtractor]
|
10
|
+
# Executes SOAP action specified as a string with given arguments.
|
11
|
+
def execute_action(action_name, args, &block)
|
12
|
+
registry = get_service_registry()
|
13
|
+
validator = AdsCommonForBingAds::ParametersValidator.new(registry)
|
14
|
+
args = validator.validate_args(action_name, args)
|
15
|
+
response = execute_soap_request(
|
16
|
+
action_name.to_sym, args, validator.extra_namespaces)
|
17
|
+
log_headers(response.http.headers)
|
18
|
+
handle_errors(response)
|
19
|
+
extractor = AdsCommon::ResultsExtractor.new(registry)
|
20
|
+
result = extractor.extract_result(response, action_name, &block)
|
21
|
+
run_user_block(extractor, response, result, &block) if block_given?
|
22
|
+
return result
|
23
|
+
end
|
24
|
+
|
25
|
+
# Adds namespace to the given string.
|
26
|
+
#
|
27
|
+
# Args:
|
28
|
+
# - str: String to prepend with a namespace
|
29
|
+
#
|
30
|
+
# Returns:
|
31
|
+
# - String with a namespace
|
32
|
+
#
|
33
|
+
def prepend_namespace(str, namespace = AdsCommonForBingAds::SavonHeaders::BaseHeaderHandler::DEFAULT_NAMESPACE)
|
34
|
+
return "%s:%s" % [namespace, str]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Executes the SOAP request with original SOAP name.
|
38
|
+
def execute_soap_request(action, args, extra_namespaces)
|
39
|
+
ns = AdsCommonForBingAds::SavonHeaders::BaseHeaderHandler::DEFAULT_NAMESPACE
|
40
|
+
original_input_name = get_service_registry.get_method_signature(action)[:input][:name].to_s.camelize
|
41
|
+
original_action_name = get_service_registry.get_method_signature(action)[:original_name].to_s.camelize
|
42
|
+
original_action_name = action if original_action_name.nil?
|
43
|
+
args = args.first if args.is_a?(Array)
|
44
|
+
additional_headers = args.delete(:headers) unless args.nil?
|
45
|
+
prepend_namespace_to_hash(args, ns)
|
46
|
+
prepend_namespace_to_hash(additional_headers, ns)
|
47
|
+
puts "**************************************args = #{args}"
|
48
|
+
response = @client.request(ns, original_input_name) do |soap|
|
49
|
+
@client.http.headers["SOAPAction"] = original_action_name
|
50
|
+
soap.body = args
|
51
|
+
set_headers(soap, extra_namespaces)
|
52
|
+
soap.header.merge!(additional_headers) if additional_headers.is_a?(Hash)
|
53
|
+
end
|
54
|
+
return response
|
55
|
+
end
|
56
|
+
def prepend_namespace_to_hash h, namespace
|
57
|
+
if h.is_a?(Hash)
|
58
|
+
h.dup.each do |k,v|
|
59
|
+
h.delete(k)
|
60
|
+
if k.to_s=~/!$/ || k.to_s=~/:/ #on ne transforme pas les noms finissant par ! ou contenant : (exemple: attributes! ou xsi:type)
|
61
|
+
h[k] = prepend_namespace_to_hash(v, namespace)
|
62
|
+
else
|
63
|
+
h[k.to_s=~ /^#{namespace}:/ ? k : prepend_namespace(k.to_s.camelize, namespace)] = prepend_namespace_to_hash(v, namespace)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
elsif h.is_a?(Array) # e.g: h = {:campaigns => {:campaign => [{:name => 'foo'}, {:name => 'foofoo'}]}}
|
67
|
+
h.map!{|e| prepend_namespace_to_hash(e, namespace)}
|
68
|
+
end
|
69
|
+
return h
|
70
|
+
end
|
71
|
+
|
72
|
+
# Creates and sets up Savon client.
|
73
|
+
def create_savon_client(endpoint, namespace)
|
74
|
+
Nori.advanced_typecasting = false
|
75
|
+
client = Savon::Client.new do |wsdl, httpi|
|
76
|
+
wsdl.endpoint = endpoint
|
77
|
+
wsdl.namespace = namespace
|
78
|
+
wsdl.element_form_default = :qualified
|
79
|
+
AdsCommonForBingAds::Http.configure_httpi(@config, httpi)
|
80
|
+
end
|
81
|
+
client.config.raise_errors = false
|
82
|
+
client.config.logger.subject = get_logger()
|
83
|
+
return client
|
84
|
+
end
|
85
|
+
|
86
|
+
# Finds an exception object for a given response.
|
87
|
+
def exception_for_soap_fault(response)
|
88
|
+
begin
|
89
|
+
fault = response[:fault]
|
90
|
+
if fault[:detail] and fault[:detail][:api_exception_fault]
|
91
|
+
exception_fault = fault[:detail][:api_exception_fault]
|
92
|
+
exception_name = exception_fault[:application_exception_type]
|
93
|
+
exception_class = get_module().const_get(exception_name)
|
94
|
+
return exception_class.new(exception_fault)
|
95
|
+
# Specific to Bing Ads
|
96
|
+
elsif fault[:detail] and fault[:detail][:api_fault]
|
97
|
+
operation_error = fault[:detail][:api_fault][:operation_errors][:operation_error]
|
98
|
+
operation_error = operation_error.first if operation_error.is_a?(Array) # if we get several errors, we only raise the first one
|
99
|
+
if exception_name = BingAdsApi::Errors::CODES[operation_error[:code]]
|
100
|
+
exception_class = BingAdsApi::Errors.const_get(exception_name)
|
101
|
+
else
|
102
|
+
raise Exception.new("code #{operation_error[:code]}")
|
103
|
+
end
|
104
|
+
return exception_class.new("#{operation_error[:message]} (#{operation_error[:details]})")
|
105
|
+
# Specific to Bing Ads (batches)
|
106
|
+
elsif fault[:detail] and fault[:detail][:api_fault_detail]
|
107
|
+
operation_error = fault[:detail][:api_fault_detail][:batch_errors][:batch_error]
|
108
|
+
operation_error = operation_error.first if operation_error.is_a?(Array) # if we get several errors, we only raise the first one
|
109
|
+
if exception_name = BingAdsApi::Errors::CODES[operation_error[:code]]
|
110
|
+
exception_class = BingAdsApi::Errors.const_get(exception_name)
|
111
|
+
else
|
112
|
+
raise Exception.new("code #{operation_error[:code]}")
|
113
|
+
end
|
114
|
+
return exception_class.new("#{operation_error[:message]} (#{operation_error[:details]})")
|
115
|
+
# Specific to Bing Ads (ad api)
|
116
|
+
elsif fault[:detail] and fault[:detail][:ad_api_fault_detail]
|
117
|
+
operation_error = fault[:detail][:ad_api_fault_detail][:errors][:ad_api_error]
|
118
|
+
operation_error = operation_error.first if operation_error.is_a?(Array) # if we get several errors, we only raise the first one
|
119
|
+
if exception_name = BingAdsApi::Errors::CODES[operation_error[:code]]
|
120
|
+
exception_class = BingAdsApi::Errors.const_get(exception_name)
|
121
|
+
else
|
122
|
+
raise Exception.new("code #{operation_error[:code]}")
|
123
|
+
end
|
124
|
+
return exception_class.new("#{operation_error[:message]} (#{operation_error[:details]})")
|
125
|
+
elsif fault[:faultstring]
|
126
|
+
fault_message = fault[:faultstring]
|
127
|
+
return AdsCommonForBingAds::Errors::ApiException.new(
|
128
|
+
"Unknown exception with error: %s" % fault_message)
|
129
|
+
else
|
130
|
+
raise ArgumentError.new(fault.to_s)
|
131
|
+
end
|
132
|
+
rescue Exception => e
|
133
|
+
operation_error ||= response[:fault][:detail][:api_fault][:operation_errors][:operation_error] rescue {}
|
134
|
+
return AdsCommonForBingAds::Errors::ApiException.new(
|
135
|
+
"Failed to resolve exception (%s), details: %s, SOAP fault: %s" %
|
136
|
+
[e.message, "#{operation_error[:message]} (#{operation_error[:details]})", response.soap_fault])
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
end
|