bing_ads_api 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/README.md +57 -0
  2. data/lib/ads_common_for_bing_ads.rb +49 -0
  3. data/lib/ads_common_for_bing_ads/api_config.rb +41 -0
  4. data/lib/ads_common_for_bing_ads/auth/client_login_handler.rb +168 -0
  5. data/lib/ads_common_for_bing_ads/build/savon_registry.rb +15 -0
  6. data/lib/ads_common_for_bing_ads/parameters_validator.rb +36 -0
  7. data/lib/ads_common_for_bing_ads/savon_headers_base_header_handler.rb +9 -0
  8. data/lib/ads_common_for_bing_ads/savon_service.rb +141 -0
  9. data/lib/bing_ads_api.rb +175 -0
  10. data/lib/bing_ads_api/api_config.rb +162 -0
  11. data/lib/bing_ads_api/client_login_header_handler.rb +21 -0
  12. data/lib/bing_ads_api/credential_handler.rb +91 -0
  13. data/lib/bing_ads_api/errors.rb +564 -0
  14. data/lib/bing_ads_api/report_header_handler.rb +46 -0
  15. data/lib/bing_ads_api/report_utils.rb +202 -0
  16. data/lib/bing_ads_api/v7/administration_service.rb +37 -0
  17. data/lib/bing_ads_api/v7/administration_service_registry.rb +30 -0
  18. data/lib/bing_ads_api/v7/campaign_management_service.rb +398 -0
  19. data/lib/bing_ads_api/v7/campaign_management_service_registry.rb +30 -0
  20. data/lib/bing_ads_api/v7/customer_billing_service.rb +58 -0
  21. data/lib/bing_ads_api/v7/customer_billing_service_registry.rb +30 -0
  22. data/lib/bing_ads_api/v7/customer_management_service.rb +98 -0
  23. data/lib/bing_ads_api/v7/customer_management_service_registry.rb +30 -0
  24. data/lib/bing_ads_api/v7/notification_service.rb +38 -0
  25. data/lib/bing_ads_api/v7/notification_service_registry.rb +30 -0
  26. data/lib/bing_ads_api/v7/reporting_service.rb +38 -0
  27. data/lib/bing_ads_api/v7/reporting_service_registry.rb +30 -0
  28. data/lib/bing_ads_api/v8/ad_intelligence_service.rb +86 -0
  29. data/lib/bing_ads_api/v8/ad_intelligence_service_registry.rb +30 -0
  30. data/lib/bing_ads_api/v8/administration_service.rb +38 -0
  31. data/lib/bing_ads_api/v8/administration_service_registry.rb +30 -0
  32. data/lib/bing_ads_api/v8/bulk_service.rb +42 -0
  33. data/lib/bing_ads_api/v8/bulk_service_registry.rb +30 -0
  34. data/lib/bing_ads_api/v8/campaign_management_service.rb +390 -0
  35. data/lib/bing_ads_api/v8/campaign_management_service_registry.rb +30 -0
  36. data/lib/bing_ads_api/v8/customer_billing_service.rb +62 -0
  37. data/lib/bing_ads_api/v8/customer_billing_service_registry.rb +30 -0
  38. data/lib/bing_ads_api/v8/customer_management_service.rb +162 -0
  39. data/lib/bing_ads_api/v8/customer_management_service_registry.rb +30 -0
  40. data/lib/bing_ads_api/v8/notification_service.rb +38 -0
  41. data/lib/bing_ads_api/v8/notification_service_registry.rb +30 -0
  42. data/lib/bing_ads_api/v8/optimizer_service.rb +46 -0
  43. data/lib/bing_ads_api/v8/optimizer_service_registry.rb +30 -0
  44. data/lib/bing_ads_api/v8/reporting_service.rb +38 -0
  45. data/lib/bing_ads_api/v8/reporting_service_registry.rb +30 -0
  46. data/lib/bing_ads_api/version.rb +5 -0
  47. data/rakefile.rb +54 -0
  48. metadata +156 -0
@@ -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,9 @@
1
+
2
+ class AdsCommonForBingAds::SavonHeaders::BaseHeaderHandler
3
+
4
+ # Generates SOAP headers with the default request header element.
5
+ def generate_headers(request, soap)
6
+ soap.header.merge!(generate_request_header())
7
+ end
8
+
9
+ 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