bing-ads-api 0.1.0

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 (75) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +92 -0
  3. data/Rakefile +38 -0
  4. data/lib/bing-ads-api.rb +38 -0
  5. data/lib/bing-ads-api.yml +345 -0
  6. data/lib/bing-ads-api/api_exception.rb +42 -0
  7. data/lib/bing-ads-api/client_proxy.rb +131 -0
  8. data/lib/bing-ads-api/config.rb +75 -0
  9. data/lib/bing-ads-api/constants.rb +133 -0
  10. data/lib/bing-ads-api/data/ad.rb +119 -0
  11. data/lib/bing-ads-api/data/ad_group.rb +121 -0
  12. data/lib/bing-ads-api/data/campaign.rb +40 -0
  13. data/lib/bing-ads-api/data/report_request.rb +78 -0
  14. data/lib/bing-ads-api/data/report_request_status.rb +48 -0
  15. data/lib/bing-ads-api/data/reporting/account_performance_report_request.rb +176 -0
  16. data/lib/bing-ads-api/data/reporting/campaign_performance_report_request.rb +186 -0
  17. data/lib/bing-ads-api/data/reporting/helpers/column_helper.rb +65 -0
  18. data/lib/bing-ads-api/data/reporting/helpers/filter_helper.rb +124 -0
  19. data/lib/bing-ads-api/data/reporting/helpers/scope_helper.rb +51 -0
  20. data/lib/bing-ads-api/data/reporting/helpers/time_helper.rb +69 -0
  21. data/lib/bing-ads-api/data/reporting/performance_report_request.rb +78 -0
  22. data/lib/bing-ads-api/data_object.rb +35 -0
  23. data/lib/bing-ads-api/fault/ad_api_error.rb +15 -0
  24. data/lib/bing-ads-api/fault/ad_api_fault_detail.rb +67 -0
  25. data/lib/bing-ads-api/fault/api_fault_detail.rb +97 -0
  26. data/lib/bing-ads-api/fault/application_fault.rb +18 -0
  27. data/lib/bing-ads-api/fault/batch_error.rb +47 -0
  28. data/lib/bing-ads-api/fault/operation_error.rb +22 -0
  29. data/lib/bing-ads-api/fault/partial_errors.rb +75 -0
  30. data/lib/bing-ads-api/service.rb +174 -0
  31. data/lib/bing-ads-api/service/campaign_management.rb +483 -0
  32. data/lib/bing-ads-api/service/reporting.rb +101 -0
  33. data/lib/bing-ads-api/soap_hasheable.rb +143 -0
  34. data/lib/bing-ads-api/version.rb +6 -0
  35. data/lib/locales/es.yml +174 -0
  36. data/lib/tasks/bing-ads-api_tasks.rake +4 -0
  37. data/test/bing-ads-api_test.rb +134 -0
  38. data/test/campaign_management_test.rb +463 -0
  39. data/test/data_object_test.rb +46 -0
  40. data/test/dummy/README.rdoc +261 -0
  41. data/test/dummy/Rakefile +7 -0
  42. data/test/dummy/app/assets/javascripts/application.js +15 -0
  43. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  44. data/test/dummy/app/controllers/application_controller.rb +3 -0
  45. data/test/dummy/app/helpers/application_helper.rb +2 -0
  46. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  47. data/test/dummy/config.ru +4 -0
  48. data/test/dummy/config/application.rb +56 -0
  49. data/test/dummy/config/boot.rb +10 -0
  50. data/test/dummy/config/database.yml +25 -0
  51. data/test/dummy/config/environment.rb +5 -0
  52. data/test/dummy/config/environments/development.rb +37 -0
  53. data/test/dummy/config/environments/production.rb +67 -0
  54. data/test/dummy/config/environments/test.rb +37 -0
  55. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  56. data/test/dummy/config/initializers/inflections.rb +15 -0
  57. data/test/dummy/config/initializers/mime_types.rb +5 -0
  58. data/test/dummy/config/initializers/secret_token.rb +7 -0
  59. data/test/dummy/config/initializers/session_store.rb +8 -0
  60. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  61. data/test/dummy/config/locales/en.yml +5 -0
  62. data/test/dummy/config/routes.rb +58 -0
  63. data/test/dummy/db/development.sqlite3 +0 -0
  64. data/test/dummy/db/test.sqlite3 +0 -0
  65. data/test/dummy/log/development.log +29 -0
  66. data/test/dummy/log/test.log +3264 -0
  67. data/test/dummy/public/404.html +26 -0
  68. data/test/dummy/public/422.html +26 -0
  69. data/test/dummy/public/500.html +25 -0
  70. data/test/dummy/public/favicon.ico +0 -0
  71. data/test/dummy/script/rails +6 -0
  72. data/test/report_request_test.rb +312 -0
  73. data/test/reporting_test.rb +145 -0
  74. data/test/test_helper.rb +11 -0
  75. metadata +205 -0
@@ -0,0 +1,186 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module BingAdsApi
4
+
5
+ ##
6
+ # Public : Defines the base object for all report requests.
7
+ # Do not instantiate this object. Instead, you may instantiate one
8
+ # of the following report request objects which derives from this object to request a report.
9
+ #
10
+ # Reference: http://msdn.microsoft.com/en-us/library/bing-ads-reporting-bing-ads-reportrequest.aspx
11
+ #
12
+ # Author:: jlopezn@neonline.cl
13
+ #
14
+ # === Usage
15
+ #
16
+ # request = BingAdsApi::CampaignPerformanceReportRequest.new(
17
+ # :format => :xml,
18
+ # :language => :english,
19
+ # :report_name => "Me report",
20
+ # :aggregation => :hourly,
21
+ # :columns => [:account_name, :account_number, :time_period],
22
+ # # The filter is specified as a hash
23
+ # :filter => {
24
+ # # specifies the Bing expected String value
25
+ # :ad_distribution => "Search",
26
+ # # specifies criteria as a snake case symbol
27
+ # :device_os => :android,
28
+ # :device_type => :tablet,
29
+ # # criteria nil is similar to not specify it at all
30
+ # :status => nil },
31
+ # :scope => {
32
+ # :account_ids => [123456, 234567],
33
+ # :campaigns => [<BingAdsApi::CampaignReportScope>] },
34
+ # # predefined date
35
+ # :time => :this_week)
36
+ #
37
+ # request2 = BingAdsApi::CampaignPerformanceReportRequest.new(
38
+ # :format => :csv,
39
+ # :language => :french,
40
+ # :report_name => "Me report",
41
+ # :aggregation => :daily,
42
+ # :columns => [:account_name, :account_number, :time_period],
43
+ # # no filter is specified
44
+ # :scope => {
45
+ # :account_ids => [123456, 234567],
46
+ # :campaigns => [<BingAdsApi::CampaignReportScope>] },
47
+ # # Custom date range
48
+ # :time => {
49
+ # :custom_date_range_start => {:day => 1, :month => 12, :year => 2013},
50
+ # :custom_date_range_end => {:day => 12, :month => 12, :year => 2013} }
51
+ # )
52
+ class CampaignPerformanceReportRequest < BingAdsApi::PerformanceReportRequest
53
+
54
+ # Valid Columns for this report request
55
+ COLUMNS = BingAdsApi::Config.instance.
56
+ reporting_constants['campaign_performance_report']['columns']
57
+
58
+ # Valid Filters for this report request
59
+ FILTERS = BingAdsApi::Config.instance.
60
+ reporting_constants['campaign_performance_report']['filter']
61
+
62
+
63
+ # Public : Constructor. Adds a validations for the columns, filter
64
+ # and scope attributes
65
+ #
66
+ # Author:: jlopezn@neonline.cl
67
+ #
68
+ # === Parameters
69
+ # * +attributes+ - Hash with the report request attributes
70
+ #
71
+ # === Example
72
+ #
73
+ # request = BingAdsApi::CampaignPerformanceReportRequest.new(
74
+ # :format => :xml,
75
+ # :language => :english,
76
+ # :report_name => "Me report",
77
+ # :aggregation => :hourly,
78
+ # :columns => [:account_name, :account_number, :time_period],
79
+ # # The filter is specified as a hash
80
+ # :filter => {
81
+ # # specifies the Bing expected String value
82
+ # :ad_distribution => "Search",
83
+ # # specifies criteria as a snake case symbol
84
+ # :device_os => :android,
85
+ # :device_type => :tablet,
86
+ # # criteria nil is similar to not specify it at all
87
+ # :status => nil },
88
+ # :scope => {
89
+ # :account_ids => [123456, 234567],
90
+ # :campaigns => [<BingAdsApi::CampaignReportScope>] },
91
+ # # predefined date
92
+ # :time => :this_week)
93
+ #
94
+ # request2 = BingAdsApi::CampaignPerformanceReportRequest.new(
95
+ # :format => :csv,
96
+ # :language => :french,
97
+ # :report_name => "Me report",
98
+ # :aggregation => :daily,
99
+ # :columns => [:account_name, :account_number, :time_period],
100
+ # # no filter is specified
101
+ # :scope => {
102
+ # :account_ids => [123456, 234567],
103
+ # :campaigns => [<BingAdsApi::CampaignReportScope>] },
104
+ # # Custom date range
105
+ # :time => {
106
+ # :custom_date_range_start => {:day => 1, :month => 12, :year => 2013},
107
+ # :custom_date_range_end => {:day => 12, :month => 12, :year => 2013} }
108
+ # )
109
+ def initialize(attributes={})
110
+ raise Exception.new("Invalid columns") if !valid_columns(COLUMNS, attributes[:columns])
111
+ raise Exception.new("Invalid filters") if !valid_filter(FILTERS, attributes[:filter])
112
+ raise Exception.new("Invalid scope") if !valid_scope(attributes[:scope])
113
+ super(attributes)
114
+ end
115
+
116
+
117
+ # Public:: Returns the object as a Hash valid for SOAP requests
118
+ #
119
+ # Author:: jlopezn@neonline.cl
120
+ #
121
+ # === Parameters
122
+ # * +keys_case+ - case for the hashes keys: underscore or camelcase
123
+ #
124
+ # Returns:: Hash
125
+ def to_hash(keys = :underscore)
126
+ hash = super(keys)
127
+ hash[get_attribute_key('columns', keys)] =
128
+ columns_to_hash(COLUMNS, columns, keys)
129
+ hash[get_attribute_key('filter', keys)] =
130
+ filter_to_hash(FILTERS, keys)
131
+ hash[get_attribute_key('scope', keys)] = scope_to_hash(keys)
132
+ hash["@xsi:type"] = type_attribute_for_soap
133
+ return hash
134
+ end
135
+
136
+
137
+ private
138
+
139
+ # Internal:: Validates the scope attribute given in the constructor
140
+ #
141
+ # Author:: jlopezn@neonline.cl
142
+ #
143
+ # === Parameters
144
+ # * +scope+ - value for the 'scope' key in the has initializer
145
+ #
146
+ # Returns:: true if the scope specification is valid. Raises Exception otherwise
147
+ #
148
+ # Raises:: Exception if the scope is not valid
149
+ def valid_scope(scope)
150
+ raise Exception.new("Invalid scope: no account_ids key") if !scope.key?(:account_ids)
151
+ raise Exception.new("Invalid scope: no campaigns key") if !scope.key?(:campaigns)
152
+ return true
153
+ end
154
+
155
+
156
+ # Internal:: Returns the scope attribute as a hash for the SOAP request
157
+ #
158
+ # Author:: jlopezn@neonline.cl
159
+ #
160
+ # === Parameters
161
+ # * +keys_case+ - case for the hash: underscore or camelcase
162
+ #
163
+ # Returns:: Hash
164
+ def scope_to_hash(keys_case=:underscore)
165
+ return {
166
+ get_attribute_key('account_ids', keys_case) => {"ins0:long" => object_to_hash(scope[:account_ids], keys_case)},
167
+ get_attribute_key('campaigns', keys_case) =>
168
+ { "CampaignReportScope" => object_to_hash(scope[:campaigns], keys_case) }
169
+ }
170
+ end
171
+
172
+
173
+ # Internal:: Returns a string with type attribute for the ReportRequest SOAP tag
174
+ #
175
+ # Author:: jlopezn@neonline.cl
176
+ #
177
+ # Returns:: "v9:CampaignPerformanceReportRequest"
178
+ def type_attribute_for_soap
179
+ return BingAdsApi::ClientProxy::NAMESPACE.to_s + ":" +
180
+ BingAdsApi::Config.instance.
181
+ reporting_constants['campaign_performance_report']['type']
182
+ end
183
+
184
+ end
185
+
186
+ end
@@ -0,0 +1,65 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module BingAdsApi::Helpers
4
+
5
+ ##
6
+ # Public : Utility module
7
+ #
8
+ # Author:: jlopezn@neonline.cl
9
+ #
10
+ module ColumnHelper
11
+
12
+ # Internal : Validates the specified columns at the ReporRequest initialization
13
+ # At the first invalid column detected this method raises Exception.
14
+ # If all column values are ok, this method returns true
15
+ # Valid columns are validated against COLUMNS constant
16
+ #
17
+ # Author:: jlopezn@neonline.cl
18
+ #
19
+ # valid_columns - Hash with the valid names and values for columns
20
+ # columns - Hash with the columns specified in the initialization
21
+ #
22
+ # Returns:: true if all columns are ok
23
+ # Raises:: Exception at the first invalid column detected
24
+ def valid_columns(valid_columns, columns)
25
+ columns.each do |col|
26
+
27
+ if col.is_a?(String)
28
+ if !valid_columns.value?(col)
29
+ raise Exception.new("Invalid column value '#{col}'")
30
+ end
31
+ elsif col.is_a?(Symbol)
32
+ if !valid_columns.key?(col.to_s)
33
+ raise Exception.new("Invalid column name '#{col}'")
34
+ end
35
+ end
36
+ end
37
+ return true
38
+ end
39
+
40
+
41
+ # Public : Return the columns attribute of the ReportRequest as a valid Hash for SOAP requests
42
+ #
43
+ # Author:: jlopezn@neonline.cl
44
+ #
45
+ # keys_case - specifies the keys_case for the hash: :underscore or :camelcase
46
+ #
47
+ # Returns:: Hash
48
+ def columns_to_hash(valid_columns, columns, keys_case=:underscore)
49
+ raise Exception.new("Invalid time value: nil") if columns.nil?
50
+
51
+ key = self.class.to_s.demodulize.gsub(/ReportRequest/, 'ReportColumn')
52
+ return { key =>
53
+ columns.map do |col|
54
+ if col.is_a?(String)
55
+ col
56
+ elsif col.is_a?(Symbol)
57
+ valid_columns[col.to_s]
58
+ end
59
+ end
60
+ }
61
+ end
62
+
63
+
64
+ end
65
+ end
@@ -0,0 +1,124 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module BingAdsApi::Helpers
4
+
5
+ ##
6
+ # Public : Utility module for filter attribute in +ReportRequest+ derived classes
7
+ #
8
+ # Author:: jlopezn@neonline.cl
9
+ #
10
+ module FilterHelper
11
+
12
+ include BingAdsApi::SOAPHasheable
13
+
14
+
15
+ # Valid filters values for each known criteria
16
+ FILTERS_CRITERIA = BingAdsApi::Config.instance.
17
+ reporting_constants['filters']
18
+
19
+
20
+ # Internal : Validates the filter attribute at the ReporRequest initialization
21
+ # At the first invalid filter criteria or value detected this method raises Exception.
22
+ # If all filter criteria and values are ok, this method returns true
23
+ # Valid filter criteria are validated against FILTERS_CRITERIA constant
24
+ # Valid filter values are validated against FILTERS constant
25
+ #
26
+ # Author:: jlopezn@neonline.cl
27
+ #
28
+ # === Parameters
29
+ # valid_filters - Hash with the set of valid filter values
30
+ # filter - Hash with the filter criteria and values
31
+ #
32
+ # Returns:: true if filter is valid
33
+ #
34
+ # Raises:: Exception at the first invalid filter criteria o value
35
+ def valid_filter(valid_filters, filter)
36
+ if filter && filter.is_a?(Hash)
37
+ filter.keys.each do |filter_key|
38
+ # validates if filter criteria is recognized
39
+ raise Exception.new("Invalid filter criteria '#{filter_key.to_s}'") if !valid_filters.key?(filter_key.to_s)
40
+ # validates the filter criteria value
41
+ valid_filter_value(filter_key, filter[filter_key])
42
+ end
43
+ end
44
+ return true
45
+ end
46
+
47
+
48
+ # Internal : Validates a specific filter criteria and his value
49
+ #
50
+ # Author:: jlopezn@neonline.cl
51
+ #
52
+ # key - filter criteria to evaluate
53
+ # value - filter criteria to be evaluate
54
+ #
55
+ # Returns:: true if validation runs ok. Raise exception otherwise
56
+ #
57
+ # Raises:: Exception if filter value provided is not valid
58
+ def valid_filter_value(key, value)
59
+ return true if value.nil?
60
+ return true if solve_filter_value(key, value)
61
+ end
62
+
63
+
64
+ # Public : Returns the filter attribute as a Hash to SOAP requests
65
+ #
66
+ # Author:: jlopezn@neonline.cl
67
+ #
68
+ # filter - Hash with the filter values
69
+ #
70
+ # Returns:: Hash
71
+ def filter_to_hash(valid_filters, keys_case=:undescore)
72
+ hashed_filter = {}
73
+ filter.each do |key, value|
74
+ hashed_filter[get_attribute_key(key, keys_case)] = solve_filter_value(key, value)
75
+ end
76
+ return hashed_filter
77
+ end
78
+
79
+
80
+ # Internal:: Solves the Bing value for the given filter attribute
81
+ #
82
+ # Author:: jlopezn@neonline.cl
83
+ #
84
+ # === Parameters
85
+ # * +filter_criteria+ - String or symbol with the filter attribute to be solved
86
+ #
87
+ # === Examples
88
+ # solve_filter_value(:ad_distribution, :search)
89
+ # # => "Search"
90
+ #
91
+ # solve_filter_value(:ad_distribution, :other)
92
+ # # => Exception "Invalid filter name 'other' for 'ad_distribution' criteria"
93
+ #
94
+ # solve_filter_value(:ad_distribution, "Search")
95
+ # # => "Search"
96
+ #
97
+ # solve_filter_value(:ad_distribution, "Other")
98
+ # # => Exception "Invalid filter value 'Other' for 'ad_distribution' criteria"
99
+ #
100
+ # Returns:: String with the Bing value for the filter criteria.
101
+ #
102
+ # Raises:: Exception if the filter's criteria or value are unknown
103
+ def solve_filter_value(filter_criteria, filter_value)
104
+
105
+ filter_criteria_values = FILTERS_CRITERIA[filter_criteria.to_s]
106
+ if filter_value.is_a?(String)
107
+ if filter_criteria_values.value?(filter_value)
108
+ return filter_value
109
+ else
110
+ raise Exception.new("Invalid filter value '#{filter_value}' for '#{filter_criteria}' criteria")
111
+ end
112
+ elsif filter_value.is_a?(Symbol)
113
+ if filter_criteria_values.key?(filter_value.to_s)
114
+ return filter_criteria_values[filter_value.to_s]
115
+ else
116
+ raise Exception.new("Invalid filter name '#{filter_value}' for '#{filter_criteria}' criteria")
117
+ end
118
+ end
119
+ return nil
120
+ end
121
+
122
+
123
+ end
124
+ end
@@ -0,0 +1,51 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module BingAdsApi::Helpers
4
+
5
+ ##
6
+ # Public : Utility module for scope attribute in +ReportRequest+ derived classes
7
+ #
8
+ # Author:: jlopezn@neonline.cl
9
+ #
10
+ module ScopeHelper
11
+
12
+ include BingAdsApi::SOAPHasheable
13
+
14
+
15
+ # Valid filters values for each known criteria
16
+ FILTERS_CRITERIA = BingAdsApi::Config.instance.
17
+ reporting_constants['filters']
18
+
19
+
20
+ # Internal : Validates the filter attribute at the ReporRequest initialization
21
+ # At the first invalid filter criteria or value detected this method raises Exception.
22
+ # If all filter criteria and values are ok, this method returns true
23
+ # Valid filter criteria are validated against FILTERS_CRITERIA constant
24
+ # Valid filter values are validated against FILTERS constant
25
+ #
26
+ # Author:: jlopezn@neonline.cl
27
+ #
28
+ # === Parameters
29
+ # valid_filters - Hash with the set of valid filter values
30
+ # filter - Hash with the filter criteria and values
31
+ #
32
+ # Returns:: true if filter is valid
33
+ #
34
+ # Raises:: Exception at the first invalid filter criteria o value
35
+ def valid_scope(valid_scopes, scope)
36
+ end
37
+
38
+
39
+ # Public : Returns the filter attribute as a Hash to SOAP requests
40
+ #
41
+ # Author:: jlopezn@neonline.cl
42
+ #
43
+ # filter - Hash with the filter values
44
+ #
45
+ # Returns:: Hash
46
+ def scope_to_hash(keys_case=:undescore)
47
+ end
48
+
49
+
50
+ end
51
+ end
@@ -0,0 +1,69 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module BingAdsApi::Helpers
4
+
5
+ ##
6
+ # Public : Utility module
7
+ #
8
+ # Author:: jlopezn@neonline.cl
9
+ #
10
+ module TimeHelper
11
+
12
+ # Valid languages for reports
13
+ TIME_PERIODS = BingAdsApi::Config.instance.
14
+ reporting_constants['time_periods']
15
+
16
+ # Public : Validates the time attribute present in some report request
17
+ #
18
+ # Author:: jlopezn@neonline.cl
19
+ #
20
+ # time - Hash with the time attribute for the report request
21
+ #
22
+ # Returns:: true if validation is ok, raises Exception otherwise
23
+ # Raises:: Exception if custom date range is bad informed, or if time periods specified is unknown
24
+ def valid_time(time)
25
+ # Custom date range
26
+ if time.is_a?(Hash)
27
+ raise Exception.new("Invalid time: missing :custom_date_range_start key") if !time.key?(:custom_date_range_start)
28
+ raise Exception.new("Invalid time: missing :custom_date_range_end key") if !time.key?(:custom_date_range_end)
29
+ # Time periods
30
+ else
31
+ return TIME_PERIODS.key?(time.to_s)
32
+ end
33
+ return true
34
+ end
35
+
36
+
37
+ # Public : Return the time attribute of the ReportRequest as a valid Hash for SOAP requests
38
+ #
39
+ # Author:: jlopezn@neonline.cl
40
+ #
41
+ # keys_case - specifies the keys_case for the hash: :underscore or :camelcase
42
+ #
43
+ # Returns:: Hash
44
+ def time_to_hash(keys_case)
45
+ raise Exception.new("Invalid time value: nil") if self.time.nil?
46
+
47
+ # Custom date range
48
+ if time.is_a?(Hash)
49
+ return {
50
+ get_attribute_key("custom_date_range_end", keys_case) => {
51
+ get_attribute_key("day", keys_case) => self.time[:custom_date_range_end][:day],
52
+ get_attribute_key("month", keys_case) => self.time[:custom_date_range_end][:month],
53
+ get_attribute_key("year", keys_case) => self.time[:custom_date_range_end][:year],
54
+
55
+ },
56
+ get_attribute_key("custom_date_range_start", keys_case) => {
57
+ get_attribute_key("day", keys_case) => self.time[:custom_date_range_start][:day],
58
+ get_attribute_key("month", keys_case) => self.time[:custom_date_range_start][:month],
59
+ get_attribute_key("year", keys_case) => self.time[:custom_date_range_start][:year],
60
+ }
61
+ }
62
+ # Time periods
63
+ else
64
+ return TIME_PERIODS[time.to_s]
65
+ end
66
+ end
67
+
68
+ end
69
+ end