adcenter_api 0.0.1

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.
Files changed (47) hide show
  1. data/README.md +57 -0
  2. data/lib/adcenter_api.rb +180 -0
  3. data/lib/adcenter_api/api_config.rb +163 -0
  4. data/lib/adcenter_api/client_login_header_handler.rb +70 -0
  5. data/lib/adcenter_api/credential_handler.rb +104 -0
  6. data/lib/adcenter_api/errors.rb +565 -0
  7. data/lib/adcenter_api/report_header_handler.rb +46 -0
  8. data/lib/adcenter_api/report_utils.rb +203 -0
  9. data/lib/adcenter_api/v7/administration_service.rb +38 -0
  10. data/lib/adcenter_api/v7/administration_service_registry.rb +30 -0
  11. data/lib/adcenter_api/v7/campaign_management_service.rb +398 -0
  12. data/lib/adcenter_api/v7/campaign_management_service_registry.rb +30 -0
  13. data/lib/adcenter_api/v7/customer_billing_service.rb +58 -0
  14. data/lib/adcenter_api/v7/customer_billing_service_registry.rb +30 -0
  15. data/lib/adcenter_api/v7/customer_management_service.rb +98 -0
  16. data/lib/adcenter_api/v7/customer_management_service_registry.rb +30 -0
  17. data/lib/adcenter_api/v7/notification_service.rb +38 -0
  18. data/lib/adcenter_api/v7/notification_service_registry.rb +30 -0
  19. data/lib/adcenter_api/v7/reporting_service.rb +38 -0
  20. data/lib/adcenter_api/v7/reporting_service_registry.rb +30 -0
  21. data/lib/adcenter_api/v8/ad_intelligence_service.rb +86 -0
  22. data/lib/adcenter_api/v8/ad_intelligence_service_registry.rb +30 -0
  23. data/lib/adcenter_api/v8/administration_service.rb +38 -0
  24. data/lib/adcenter_api/v8/administration_service_registry.rb +30 -0
  25. data/lib/adcenter_api/v8/bulk_service.rb +42 -0
  26. data/lib/adcenter_api/v8/bulk_service_registry.rb +30 -0
  27. data/lib/adcenter_api/v8/campaign_management_service.rb +390 -0
  28. data/lib/adcenter_api/v8/campaign_management_service_registry.rb +30 -0
  29. data/lib/adcenter_api/v8/customer_billing_service.rb +62 -0
  30. data/lib/adcenter_api/v8/customer_billing_service_registry.rb +30 -0
  31. data/lib/adcenter_api/v8/customer_management_service.rb +162 -0
  32. data/lib/adcenter_api/v8/customer_management_service_registry.rb +30 -0
  33. data/lib/adcenter_api/v8/notification_service.rb +38 -0
  34. data/lib/adcenter_api/v8/notification_service_registry.rb +30 -0
  35. data/lib/adcenter_api/v8/optimizer_service.rb +46 -0
  36. data/lib/adcenter_api/v8/optimizer_service_registry.rb +30 -0
  37. data/lib/adcenter_api/v8/reporting_service.rb +38 -0
  38. data/lib/adcenter_api/v8/reporting_service_registry.rb +30 -0
  39. data/lib/adcenter_api/version.rb +5 -0
  40. data/lib/ads_common/api_config_decorator.rb +43 -0
  41. data/lib/ads_common/auth/client_login_handler_decorator.rb +168 -0
  42. data/lib/ads_common/build/savon_registry_decorator.rb +16 -0
  43. data/lib/ads_common/parameters_validator_decorator.rb +37 -0
  44. data/lib/ads_common/savon_headers_base_header_handler_decorator.rb +23 -0
  45. data/lib/ads_common/savon_service_decorator.rb +109 -0
  46. data/rakefile.rb +54 -0
  47. metadata +157 -0
@@ -0,0 +1,38 @@
1
+ # Encoding: utf-8
2
+ #
3
+ # This is auto-generated code, changes will be overwritten.
4
+ #
5
+ # Copyright:: Copyright 2012, Google Inc. All Rights Reserved.
6
+ # License:: Licensed under the Apache License, Version 2.0.
7
+ #
8
+ # Code generated by AdsCommon library 0.7.3 on 2012-07-04 16:50:32.
9
+
10
+ require 'ads_common/savon_service'
11
+ require 'adcenter_api/v8/reporting_service_registry'
12
+
13
+ module AdcenterApi; module V8; module ReportingService
14
+ class ReportingService < AdsCommon::SavonService
15
+ def initialize(config, endpoint)
16
+ namespace = 'https://adcenter.microsoft.com/v8'
17
+ super(config, endpoint, namespace, :v8)
18
+ end
19
+
20
+ def submit_generate_report(*args, &block)
21
+ return execute_action('submit_generate_report', args, &block)
22
+ end
23
+
24
+ def poll_generate_report(*args, &block)
25
+ return execute_action('poll_generate_report', args, &block)
26
+ end
27
+
28
+ private
29
+
30
+ def get_service_registry()
31
+ return ReportingServiceRegistry
32
+ end
33
+
34
+ def get_module()
35
+ return AdcenterApi::V8::ReportingService
36
+ end
37
+ end
38
+ end; end; end
@@ -0,0 +1,30 @@
1
+ # Encoding: utf-8
2
+ #
3
+ # This is auto-generated code, changes will be overwritten.
4
+ #
5
+ # Copyright:: Copyright 2012, Google Inc. All Rights Reserved.
6
+ # License:: Licensed under the Apache License, Version 2.0.
7
+ #
8
+ # Code generated by AdsCommon library 0.7.3 on 2012-07-04 16:50:32.
9
+
10
+ require 'adcenter_api/errors'
11
+
12
+ module AdcenterApi; module V8; module ReportingService
13
+ class ReportingServiceRegistry
14
+ REPORTINGSERVICE_METHODS = {:submit_generate_report=>{:input=>{:name=>"submit_generate_report_request", :fields=>[]}, :output=>{:name=>"submit_generate_report_response", :fields=>[]}, :original_name=>"SubmitGenerateReport"}, :poll_generate_report=>{:input=>{:name=>"poll_generate_report_request", :fields=>[]}, :output=>{:name=>"poll_generate_report_response", :fields=>[]}, :original_name=>"PollGenerateReport"}}
15
+ REPORTINGSERVICE_TYPES = {}
16
+ REPORTINGSERVICE_NAMESPACES = []
17
+
18
+ def self.get_method_signature(method_name)
19
+ return REPORTINGSERVICE_METHODS[method_name.to_sym]
20
+ end
21
+
22
+ def self.get_type_signature(type_name)
23
+ return REPORTINGSERVICE_TYPES[type_name.to_sym]
24
+ end
25
+
26
+ def self.get_namespace(index)
27
+ return REPORTINGSERVICE_NAMESPACES[index]
28
+ end
29
+ end
30
+ end; end; end
@@ -0,0 +1,5 @@
1
+ module AdcenterApi
2
+ module ApiConfig
3
+ CLIENT_LIB_VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,43 @@
1
+ ####### Overriden for Adcenter #########
2
+
3
+ AdsCommon::ApiConfig.module_eval do
4
+
5
+ # Get the endpoint for a service on a given environment and API version.
6
+ #
7
+ # Args:
8
+ # - environment: the service environment to be used
9
+ # - version: the API version
10
+ # - service: the name of the API service
11
+ #
12
+ # Returns:
13
+ # The endpoint URL
14
+ #
15
+ def endpoint(environment, version, service)
16
+ if !address_config().nil?
17
+ address_config()[version][service][environment].to_s
18
+ else
19
+ ""
20
+ end
21
+ end
22
+ # Generates an array of WSDL URLs based on defined Services and version
23
+ # supplied. This method is used by generators to determine what service
24
+ # wrappers to generate.
25
+ #
26
+ # Args:
27
+ # - version: the API version.
28
+ #
29
+ # Returns
30
+ # hash of pairs Service => WSDL URL
31
+ #
32
+ def get_wsdls(version)
33
+ res = {}
34
+ services(version).each do |service|
35
+ if (!address_config().nil?)
36
+ path = address_config()[version][service][default_environment()].to_s
37
+ end
38
+ res[service.to_s] = path || ""
39
+ end
40
+ return res
41
+ end
42
+
43
+ end
@@ -0,0 +1,168 @@
1
+ ####### Overriden for Adcenter #########
2
+
3
+ AdsCommon::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
+ # - AdsCommon::Errors::AuthError if validation fails
51
+ #
52
+ def validate_credentials(credentials)
53
+ if credentials.nil?
54
+ raise AdsCommon::Errors::AuthError, 'No credentials supplied.'
55
+ end
56
+
57
+ if credentials[:auth_token].nil?
58
+ if credentials[:user_name].nil?
59
+ raise AdsCommon::Errors::AuthError,
60
+ 'UserName address not included in credentials.'
61
+ end
62
+ if credentials[:password].nil?
63
+ raise AdsCommon::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
+ # - AdsCommon::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 = AdsCommon::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 AdsCommon::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 AdsCommon::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,16 @@
1
+ require 'ads_common/build/savon_registry'
2
+
3
+ AdsCommon::Build::SavonRegistry.class_eval do
4
+
5
+ # Extracts input parameters of given method as an array.
6
+ def extract_input_parameters(op_node, doc)
7
+ input_element = REXML::XPath.first(op_node, 'descendant::wsdl:input')
8
+ input_name = get_element_name(input_element)
9
+ input_fields = find_sequence_fields(input_name, doc)
10
+ return {:name => input_name.snakecase, :fields => input_fields}
11
+ end
12
+
13
+
14
+
15
+
16
+ end
@@ -0,0 +1,37 @@
1
+ require 'ads_common/parameters_validator'
2
+
3
+ AdsCommon::ParametersValidator.class_eval do
4
+
5
+ # Validates input parameters to:
6
+ # - add parameter names;
7
+ # - resolve xsi:type where required;
8
+ # - convert some native types to XML.
9
+ def validate_args(action_name, args)
10
+ in_params = @registry.get_method_signature(action_name)[:input] # Hash like {:name=>"get_accounts_info_request", :fields=>[]}
11
+ # TODO: compare number of parameters.
12
+ args_hash = args#{in_params[:name] => deep_copy(args)}
13
+ #validate_arguments(args_hash, in_params)
14
+ return args_hash
15
+ end
16
+
17
+ private
18
+
19
+ # Validates given arguments based on provided fields list.
20
+ def validate_arguments(args_hash, fields_list, type_ns = nil)
21
+ check_extra_fields(args_hash, array_from_named_list(fields_list))
22
+ add_order_key(args_hash, fields_list)
23
+ fields_list.each do |field|
24
+ key = field[:name]
25
+ item = args_hash[key]
26
+ check_required_argument_present(item, field)
27
+ if item
28
+ item_type = get_full_type_signature(field[:type])
29
+ item_ns = field[:ns] || type_ns
30
+ key = handle_namespace_override(args_hash, key, item_ns) if item_ns
31
+ validate_arg(item, args_hash, key, item_type)
32
+ end
33
+ end
34
+ return args_hash
35
+ end
36
+
37
+ end
@@ -0,0 +1,23 @@
1
+ ####### Overriden for Adcenter #########
2
+ require 'ads_common/savon_headers/base_header_handler'
3
+
4
+ AdsCommon::SavonHeaders::BaseHeaderHandler.class_eval do
5
+
6
+ # Generates SOAP headers with the default request header element.
7
+ def generate_headers(request, soap)
8
+ soap.header.merge!(generate_request_header())
9
+ end
10
+ # Generates SOAP default request header with all requested headers.
11
+ #def generate_request_header()
12
+ # credentials = @credential_handler.credentials
13
+ # extra_headers = credentials[:extra_headers]
14
+ # puts "extra_headers=#{extra_headers}"
15
+ # return extra_headers.inject({}) do |result, (header, value)|
16
+ # puts "header=#{header}"
17
+ # puts "value=#{value}"
18
+ # result[prepend_namespace(header)] = value
19
+ # result
20
+ # end
21
+ #end
22
+
23
+ end
@@ -0,0 +1,109 @@
1
+ ####### Overriden for Adcenter #########
2
+ require 'ads_common/savon_service'
3
+
4
+ AdsCommon::SavonService.class_eval do
5
+
6
+ private
7
+
8
+ # Adds namespace to the given string.
9
+ #
10
+ # Args:
11
+ # - str: String to prepend with a namespace
12
+ #
13
+ # Returns:
14
+ # - String with a namespace
15
+ #
16
+ def prepend_namespace(str, namespace = AdsCommon::SavonHeaders::BaseHeaderHandler::DEFAULT_NAMESPACE)
17
+ return "%s:%s" % [namespace, str]
18
+ end
19
+
20
+ # Executes the SOAP request with original SOAP name.
21
+ def execute_soap_request(action, args, extra_namespaces)
22
+ ns = AdsCommon::SavonHeaders::BaseHeaderHandler::DEFAULT_NAMESPACE
23
+ original_input_name = get_service_registry.get_method_signature(action)[:input][:name].to_s.camelize
24
+ original_action_name = get_service_registry.get_method_signature(action)[:original_name].to_s.camelize
25
+ original_action_name = action if original_action_name.nil?
26
+ args = args.first if args.is_a?(Array)
27
+ additional_headers = args.delete(:headers) unless args.nil?
28
+ prepend_namespace_to_hash(args, ns)
29
+ prepend_namespace_to_hash(additional_headers, ns)
30
+ response = @client.request(ns, original_input_name) do |soap|
31
+ @client.http.headers["SOAPAction"] = original_action_name
32
+ soap.body = args
33
+ set_headers(soap, extra_namespaces)
34
+ soap.header.merge!(additional_headers) if additional_headers.is_a?(Hash)
35
+ end
36
+ return response
37
+ end
38
+ def prepend_namespace_to_hash h, namespace
39
+ if h.is_a?(Hash)
40
+ h.dup.each do |k,v|
41
+ h.delete(k)
42
+ h[k.to_s=~ /^#{namespace}:/ ? k : prepend_namespace(k.to_s.camelize, namespace)] = prepend_namespace_to_hash(v, namespace)
43
+ end
44
+ elsif h.is_a?(Array) # e.g: h = {:campaigns => {:campaign => [{:name => 'foo'}, {:name => 'foofoo'}]}}
45
+ h.map!{|e| prepend_namespace_to_hash(e, namespace)}
46
+ end
47
+ return h
48
+ end
49
+
50
+ # Creates and sets up Savon client.
51
+ def create_savon_client(endpoint, namespace)
52
+ Nori.advanced_typecasting = false
53
+ client = Savon::Client.new do |wsdl, httpi|
54
+ wsdl.endpoint = endpoint
55
+ wsdl.namespace = namespace
56
+ wsdl.element_form_default = :qualified
57
+ AdsCommon::Http.configure_httpi(@config, httpi)
58
+ end
59
+ client.config.raise_errors = false
60
+ client.config.logger.subject = get_logger()
61
+ return client
62
+ end
63
+
64
+ # Finds an exception object for a given response.
65
+ def exception_for_soap_fault(response)
66
+ begin
67
+ fault = response[:fault]
68
+ if fault[:detail] and fault[:detail][:api_exception_fault]
69
+ exception_fault = fault[:detail][:api_exception_fault]
70
+ exception_name = exception_fault[:application_exception_type]
71
+ exception_class = get_module().const_get(exception_name)
72
+ return exception_class.new(exception_fault)
73
+ # Specific to AdCenter
74
+ elsif fault[:detail] and fault[:detail][:api_fault]
75
+ operation_error = fault[:detail][:api_fault][:operation_errors][:operation_error]
76
+ operation_error = operation_error.first if operation_error.is_a?(Array) # if we get several errors, we only raise the first one
77
+ if exception_name = AdcenterApi::Errors::CODES[operation_error[:code]]
78
+ exception_class = AdcenterApi::Errors.const_get(exception_name)
79
+ else
80
+ raise Exception.new("code #{operation_error[:code]}")
81
+ end
82
+ return exception_class.new("#{operation_error[:message]} (#{operation_error[:details]})")
83
+ # Specific to AdCenter (batches)
84
+ elsif fault[:detail] and fault[:detail][:api_fault_detail]
85
+ operation_error = fault[:detail][:api_fault_detail][:batch_errors][:batch_error]
86
+ operation_error = operation_error.first if operation_error.is_a?(Array) # if we get several errors, we only raise the first one
87
+ if exception_name = AdcenterApi::Errors::CODES[operation_error[:code]]
88
+ exception_class = AdcenterApi::Errors.const_get(exception_name)
89
+ else
90
+ raise Exception.new("code #{operation_error[:code]}")
91
+ end
92
+ return exception_class.new("#{operation_error[:message]} (#{operation_error[:details]})")
93
+ elsif fault[:faultstring]
94
+ fault_message = fault[:faultstring]
95
+ return AdsCommon::Errors::ApiException.new(
96
+ "Unknown exception with error: %s" % fault_message)
97
+ else
98
+ raise ArgumentError.new(fault.to_s)
99
+ end
100
+ rescue Exception => e
101
+ operation_error ||= response[:fault][:detail][:api_fault][:operation_errors][:operation_error] rescue {}
102
+ return AdsCommon::Errors::ApiException.new(
103
+ "Failed to resolve exception (%s), details: %s, SOAP fault: %s" %
104
+ [e.message, "#{operation_error[:message]} (#{operation_error[:details]})", response.soap_fault])
105
+ end
106
+ end
107
+
108
+
109
+ end