Skip to content
This repository has been archived by the owner on Jun 8, 2023. It is now read-only.

Adds URL Custom Parameter support & allows bid to be unchanged #8

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 33 additions & 21 deletions README.md
@@ -1,8 +1,15 @@
[![Gem Version](https://img.shields.io/gem/v/bing-ads.svg)](https://rubygems.org/gems/bing-ads)
[![Build Status](https://travis-ci.org/FindHotel/bing-ads.svg?branch=master)](https://travis-ci.org/FindHotel/bing-ads)

## We have not tested all pieces of functionality for this gem!
Please look [here](https://docs.microsoft.com/en-us/bingads/guides/migration-guide?view=bingads-13) if you're using this gem to make sure that the functionality you're looking for didn't experience a breaking change

# Bing::Ads

## An ezcater fork of a Bing Ads API client

We forked this repo in order to upgrade to API V12 (and now V13).

A Ruby client for Bing Ads API that includes a proxy to all Bing Ads API web services and abstracts low level details of authentication with OAuth.

## Installation
Expand Down Expand Up @@ -37,7 +44,7 @@ options = {
# client_settings: { logger: LOGGER::STDOUT }
}

service = Bing::Ads::API::V11::Services::CustomerManagement.new(options)
service = Bing::Ads::API::V13::Services::CustomerManagement.new(options)
```

#### Getting accounts info
Expand All @@ -60,7 +67,7 @@ options = {
# client_settings: { logger: LOGGER::STDOUT }
}

service = Bing::Ads::API::V11::Services::CampaignManagement.new(options)
service = Bing::Ads::API::V13::Services::CampaignManagement.new(options)
```

#### Getting campaigns
Expand All @@ -81,12 +88,12 @@ response = service.get_campaigns_by_ids(account_id, campaign_ids)
account_id = 5278183
campaigns = [
{
budget_type: Bing::Ads::API::V11.constants.campaign_management.budget_limit_type.daily_budget_standard,
budget_type: Bing::Ads::API::V13.constants.campaign_management.budget_limit_type.daily_budget_standard,
daily_budget: 2000,
description: 'Amsterdam-based global campaign',
name: '51 - Global - Chain - Mixed - N -en- Amsterdam - 100 - 26479',
status: Bing::Ads::API::V11.constants.campaign_management.campaign_status.paused,
time_zone: Bing::Ads::API::V11.constants.time_zones.amsterdam_berlin_bern_rome_stockholm_vienna
status: Bing::Ads::API::V13.constants.campaign_management.campaign_status.paused,
time_zone: Bing::Ads::API::V13.constants.time_zones.amsterdam_berlin_bern_rome_stockholm_vienna
},
# ...
]
Expand All @@ -100,11 +107,11 @@ account_id = 5278183
campaigns = [
{
id: 813721838,
budget_type: Bing::Ads::API::V11.constants.campaign_management.budget_limit_type.daily_budget_standard,
budget_type: Bing::Ads::API::V13.constants.campaign_management.budget_limit_type.daily_budget_standard,
},
{
id: 813721849,
budget_type: Bing::Ads::API::V11.constants.campaign_management.budget_limit_type.daily_budget_standard,
budget_type: Bing::Ads::API::V13.constants.campaign_management.budget_limit_type.daily_budget_standard,
},
# ...
]
Expand Down Expand Up @@ -141,16 +148,16 @@ response = service.get_ad_groups_by_ids(campaign_id, ad_group_ids)
campaign_id = 813721838
ad_groups = [
{
ad_distribution: Bing::Ads::API::V11.constants.campaign_management.ad_distribution.search, # required
ad_rotation: Bing::Ads::API::V11.constants.campaign_management.ad_rotation.optimize_for_clicks, # optional
bidding_scheme: Bing::Ads::API::V11.constants.campaign_management.bidding_scheme.inherit_from_parent, # optional
ad_distribution: Bing::Ads::API::V13.constants.campaign_management.ad_distribution.search, # required
ad_rotation: Bing::Ads::API::V13.constants.campaign_management.ad_rotation.optimize_for_clicks, # optional
bidding_scheme: Bing::Ads::API::V13.constants.campaign_management.bidding_scheme.inherit_from_parent, # optional
content_match_bid: 100, # optional
end_date: '31/12/2020',
status: Bing::Ads::API::V11.constants.campaign_management.ad_group_status.paused,
language: Bing::Ads::API::V11.constants.languages.english,
status: Bing::Ads::API::V13.constants.campaign_management.ad_group_status.paused,
language: Bing::Ads::API::V13.constants.languages.english,
name: 'H=WHotelAmsterdam&AG=1723812002',
native_bid_adjustment: -50, # optional (-100 to 900)
remarketing_targeting_setting: Bing::Ads::API::V11.constants.campaign_management.remarketing_target_setting.bid_only, # optional
remarketing_targeting_setting: Bing::Ads::API::V13.constants.campaign_management.remarketing_target_setting.bid_only, # optional
search_bid: 100, # optional
start_date: '5/7/2017',
},
Expand All @@ -169,7 +176,7 @@ campaign_id = 813721838
ad_groups = [
{
id: 9866221838,
status: Bing::Ads::API::V11.constants.campaign_management.ad_group_status.active
status: Bing::Ads::API::V13.constants.campaign_management.ad_group_status.active
},
# ...
]
Expand Down Expand Up @@ -205,7 +212,7 @@ response = service.get_ads_by_ids(ad_group_id, ad_ids)
ad_group_id = 9866221838
expanded_text_ads = [
{
type: Bing::Ads::API::V11.constants.campaign_management.ad_types.expanded_text_ad, # ExpandedTextAd
type: Bing::Ads::API::V13.constants.campaign_management.ad_types.expanded_text_ad, # ExpandedTextAd
path_1: 'Amsterdam',
path_2: 'Hotels',
text: 'Compare over 150 booking sites! Find guaranteed low hotel rates.',
Expand Down Expand Up @@ -270,14 +277,14 @@ response = service.get_keywords_by_ids(ad_group_id, keyword_ids)
ad_group_id = 9866221838
keywords = [
{
bidding_scheme: Bing::Ads::API::V11.constants.campaign_management.bidding_scheme.inherit_from_parent,
bidding_scheme: Bing::Ads::API::V13.constants.campaign_management.bidding_scheme.inherit_from_parent,
bid: 5,
# optional, ad final urls used if this is not set
final_urls: [
'https://www.findhotel.net/Places/Amsterdam.htm?attrs=pet-friendly'
],
match_type: Bing::Ads::API::V11.constants.campaign_management.match_types.exact, # also broad, content, phrase
status: Bing::Ads::API::V11.constants.campaign_management.keyword_statuses.active,
match_type: Bing::Ads::API::V13.constants.campaign_management.match_types.exact, # also broad, content, phrase
status: Bing::Ads::API::V13.constants.campaign_management.keyword_statuses.active,
text: 'Pet-friendly Hotels in Amsterdam'
},
# ...
Expand All @@ -296,6 +303,11 @@ ad_group_id = 9866221838
updated_keywords = [
{
id: 234873284248,
final_urls: [ '...' ],
tracking_url_template: '',
url_custom_parameters: {
foo: 'bar'
}
# updated attributes
},
# ...
Expand Down Expand Up @@ -326,7 +338,7 @@ options = {
# client_settings: { logger: LOGGER::STDOUT }
}

service = Bing::Ads::API::V11::Services::Bulk.new(options)
service = Bing::Ads::API::V13::Services::Bulk.new(options)
```

#### Submit a request for a URL where a bulk upload file may be posted.
Expand Down Expand Up @@ -368,7 +380,7 @@ options = {
# client_settings: { logger: LOGGER::STDOUT }
}

service = Bing::Ads::API::V11::Services::Reporting.new(options)
service = Bing::Ads::API::V13::Services::Reporting.new(options)
```

#### Submit Generate Report
Expand Down Expand Up @@ -400,7 +412,7 @@ The required options depend on the report type you are using.
Response example:

```ruby
{:report_request_id=>"30000000999745662", :@xmlns=>"https://bingads.microsoft.com/Reporting/v11"}
{:report_request_id=>"30000000999745662", :@xmlns=>"https://bingads.microsoft.com/Reporting/v13"}
```

#### Poll Generate Report
Expand Down
8 changes: 4 additions & 4 deletions lib/bing/ads.rb
Expand Up @@ -8,10 +8,10 @@
require 'bing/ads/api/errors'
require 'bing/ads/api/soap_client'
require 'bing/ads/api/http_client'
require 'bing/ads/api/v11'
require 'bing/ads/api/v11/constants'
require 'bing/ads/api/v11/data'
require 'bing/ads/api/v11/services'
require 'bing/ads/api/v13'
require 'bing/ads/api/v13/constants'
require 'bing/ads/api/v13/data'
require 'bing/ads/api/v13/services'

require 'bing/ads/utils'
require 'bing/ads/version'
Expand Down
7 changes: 6 additions & 1 deletion lib/bing/ads/api/http_client.rb
Expand Up @@ -7,7 +7,12 @@ class HttpClient

def self.download(url, retry_count = API_CALL_RETRY_COUNT)
1.upto(retry_count + 1) do |retry_index|
response = Net::HTTP.get_response(URI(url))
http = Net::HTTP.new(URI(url))
http.use_ssl = true
http.ssl_version = :TLSv1
http.ciphers = ['RC4-SHA']
http.get(uri.request_uri)
response = http.get_response(URI(url))
if response.is_a?(Net::HTTPSuccess)
break response.body
else
Expand Down
6 changes: 3 additions & 3 deletions lib/bing/ads/api/v11.rb → lib/bing/ads/api/v13.rb
@@ -1,9 +1,9 @@
module Bing
module Ads
module API
# Bing::Ads::API::V11
module V11
NAMESPACE_IDENTIFIER = :v11
# Bing::Ads::API::V13
module V13
NAMESPACE_IDENTIFIER = :v13

def self.constants
@_config || fail('Error loading bing ads gem')
Expand Down
Expand Up @@ -3,15 +3,15 @@
module Bing
module Ads
module API
# Bing::Ads::API::V11::Constants
# Bing::Ads::API::V13::Constants
module Constants
root_v11_path = File.expand_path('../', __FILE__)
root_v13_path = File.expand_path('../', __FILE__)

campaign_management_path = File.join(root_v11_path, 'constants', 'campaign_management.yml')
languages_path = File.join(root_v11_path, 'constants', 'languages.yml')
limits_path = File.join(root_v11_path, 'constants', 'limits.yml')
time_zones_path = File.join(root_v11_path, 'constants', 'time_zones.yml')
wsdl_path = File.join(root_v11_path, 'constants', 'wsdl.yml')
campaign_management_path = File.join(root_v13_path, 'constants', 'campaign_management.yml')
languages_path = File.join(root_v13_path, 'constants', 'languages.yml')
limits_path = File.join(root_v13_path, 'constants', 'limits.yml')
time_zones_path = File.join(root_v13_path, 'constants', 'time_zones.yml')
wsdl_path = File.join(root_v13_path, 'constants', 'wsdl.yml')

Persey.init(:default) do
source :yaml, campaign_management_path, :campaign_management
Expand All @@ -22,7 +22,7 @@ module Constants
env :default
end

Bing::Ads::API::V11.constants = Persey.config
Bing::Ads::API::V13.constants = Persey.config
end
end
end
Expand Down
@@ -1,10 +1,10 @@
sandbox:
customer_management: https://clientcenter.api.sandbox.bingads.microsoft.com/Api/CustomerManagement/v11/CustomerManagementService.svc?singleWsdl
campaign_management: "https://campaign.api.sandbox.bingads.microsoft.com/Api/Advertiser/CampaignManagement/V11/CampaignManagementService.svc?singleWsdl"
reporting: "https://api.sandbox.bingads.microsoft.com/Api/Advertiser/Reporting/V11/ReportingService.svc?singleWsdl"
bulk: 'https://bulk.api.sandbox.bingads.microsoft.com/Api/Advertiser/CampaignManagement/V11/BulkService.svc?singleWsdl'
customer_management: https://clientcenter.api.sandbox.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc?singleWsdl
campaign_management: "https://campaign.api.sandbox.bingads.microsoft.com/Api/Advertiser/CampaignManagement/V13/CampaignManagementService.svc?singleWsdl"
reporting: "https://api.sandbox.bingads.microsoft.com/Api/Advertiser/Reporting/V13/ReportingService.svc?singleWsdl"
bulk: 'https://bulk.api.sandbox.bingads.microsoft.com/Api/Advertiser/CampaignManagement/V13/BulkService.svc?singleWsdl'
production:
customer_management: https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v11/CustomerManagementService.svc?singleWsdl
campaign_management: "https://campaign.api.bingads.microsoft.com/Api/Advertiser/CampaignManagement/V11/CampaignManagementService.svc?singleWsdl"
reporting: "https://api.bingads.microsoft.com/Api/Advertiser/Reporting/V11/ReportingService.svc?singleWsdl"
bulk: 'https://bulk.api.bingads.microsoft.com/Api/Advertiser/CampaignManagement/V11/BulkService.svc?singleWsdl'
customer_management: https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc?singleWsdl
campaign_management: "https://campaign.api.bingads.microsoft.com/Api/Advertiser/CampaignManagement/V13/CampaignManagementService.svc?singleWsdl"
reporting: "https://reporting.api.bingads.microsoft.com/Api/Advertiser/Reporting/V13/ReportingService.svc?singleWsdl"
bulk: 'https://bulk.api.bingads.microsoft.com/Api/Advertiser/CampaignManagement/V13/BulkService.svc?singleWsdl'
@@ -1,9 +1,9 @@
module Bing
module Ads
module API
module V11
module V13
module Data
# Bing::Ads::API::V11::Data::AdGroup
# Bing::Ads::API::V13::Data::AdGroup
class AdGroup

# @order
Expand Down Expand Up @@ -37,7 +37,7 @@ def self.prepare(ad_group_raw)
# TODO support MaxClicksBiddingScheme, MaxConversionsBiddingScheme and TargetCpaBiddingScheme
ad_group_raw[:bidding_scheme] = {
type: ad_group_raw[:bidding_scheme],
'@xsi:type' => "#{Bing::Ads::API::V11::NAMESPACE_IDENTIFIER}:#{ad_group_raw[:bidding_scheme]}"
'@xsi:type' => "#{Bing::Ads::API::V13::NAMESPACE_IDENTIFIER}:#{ad_group_raw[:bidding_scheme]}"
}
end
ad_group_raw[:content_match_bid] = { amount: ad_group_raw[:content_match_bid] } if ad_group_raw[:content_match_bid]
Expand Down
@@ -1,9 +1,9 @@
module Bing
module Ads
module API
module V11
module V13
module Data
# Bing::Ads::API::V11::Data::Campaign
# Bing::Ads::API::V13::Data::Campaign
class Campaign

# @order
Expand Down Expand Up @@ -33,7 +33,7 @@ def self.prepare(campaign_raw)
campaign_raw[:bidding_scheme] = {
# TODO support MaxClicksBiddingScheme, MaxConversionsBiddingScheme and TargetCpaBiddingScheme
type: campaign_raw[:bidding_scheme],
'@xsi:type' => "#{Bing::Ads::API::V11::NAMESPACE_IDENTIFIER}:#{campaign_raw[:bidding_scheme]}"
'@xsi:type' => "#{Bing::Ads::API::V13::NAMESPACE_IDENTIFIER}:#{campaign_raw[:bidding_scheme]}"
}
end
# TODO UrlCustomParameters
Expand Down
@@ -1,9 +1,9 @@
module Bing
module Ads
module API
module V11
module V13
module Data
# Bing::Ads::API::V11::Data::ExpandedTextAd
# Bing::Ads::API::V13::Data::ExpandedTextAd
class ExpandedTextAd

# @order
Expand All @@ -29,7 +29,7 @@ class ExpandedTextAd
]

def self.prepare(ad_raw)
ad_raw['@xsi:type'] = "#{Bing::Ads::API::V11::NAMESPACE_IDENTIFIER}:#{ad_raw[:type]}"
ad_raw['@xsi:type'] = "#{Bing::Ads::API::V13::NAMESPACE_IDENTIFIER}:#{ad_raw[:type]}"
# TODO FinalAppUrls
ad_raw[:final_mobile_urls] = { 'ins1:string' => ad_raw[:final_mobile_urls] } if ad_raw[:final_mobile_urls]
ad_raw[:final_urls] = { 'ins1:string' => ad_raw[:final_urls] } if ad_raw[:final_urls]
Expand Down
@@ -1,9 +1,9 @@
module Bing
module Ads
module API
module V11
module V13
module Data
# Bing::Ads::API::V11::Data::Keyword
# Bing::Ads::API::V13::Data::Keyword
class Keyword

# @order
Expand Down Expand Up @@ -32,20 +32,40 @@ class Keyword
def self.prepare(keyword_raw)
# To use the AdGroup default match type bid,
# set the Amount element of the Bid object to null.
keyword_raw[:bid] = { amount: keyword_raw[:bid] }
keyword_raw[:bid] = { amount: keyword_raw[:bid] } if keyword_raw.has_key? :bid
if keyword_raw[:bidding_scheme]
# TODO support MaxClicksBiddingScheme, MaxConversionsBiddingScheme and TargetCpaBiddingScheme
keyword_raw[:bidding_scheme] = {
type: keyword_raw[:bidding_scheme],
'@xsi:type' => "#{Bing::Ads::API::V11::NAMESPACE_IDENTIFIER}:#{keyword_raw[:bidding_scheme]}"
'@xsi:type' => "#{Bing::Ads::API::V13::NAMESPACE_IDENTIFIER}:#{keyword_raw[:bidding_scheme]}"
}
end

if keyword_raw[:final_mobile_urls]
keyword_raw[:final_mobile_urls] = {
'a1:string' => keyword_raw[:final_mobile_urls],
'@xmlns:a1' => 'http://schemas.microsoft.com/2003/10/Serialization/Arrays'
}
end
if keyword_raw[:final_urls]
keyword_raw[:final_urls] = {
'a1:string' => keyword_raw[:final_urls],
'@xmlns:a1' => 'http://schemas.microsoft.com/2003/10/Serialization/Arrays'
}
end
keyword_raw[:final_mobile_urls] = { 'ins1:string' => keyword_raw[:final_mobile_urls] } if keyword_raw[:final_mobile_urls]
keyword_raw[:final_urls] = { 'ins1:string' => keyword_raw[:final_urls] } if keyword_raw[:final_urls]
# TODO FinalAppUrls
# TODO UrlCustomParameters

keyword_raw = Bing::Ads::Utils.sort_keys(keyword_raw)
Bing::Ads::Utils.camelcase_keys(keyword_raw)
if keyword_raw.has_key? :url_custom_parameters
keyword_raw['UrlCustomParameters'] = { 'Parameters' => {'CustomParameter' => []} }
keyword_raw[:url_custom_parameters].each do |k,v|
keyword_raw['UrlCustomParameters']['Parameters']['CustomParameter'].push({ 'Key' => k, 'Value' => v})
end
keyword_raw.delete :url_custom_parameters
end

keyword_raw
end
end
end
Expand Down