bing_ads_api 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|