adapi 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.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.rdoc +127 -0
- data/Rakefile +12 -0
- data/adapi.gemspec +28 -0
- data/examples/add_ad.rb +17 -0
- data/examples/add_ad_group.rb +46 -0
- data/examples/add_ad_group_criteria.rb +20 -0
- data/examples/add_bare_ad_group.rb +26 -0
- data/examples/add_bare_campaign.rb +27 -0
- data/examples/add_campaign.rb +68 -0
- data/examples/add_campaign_targets.rb +16 -0
- data/examples/custom_settings.yml +22 -0
- data/examples/customize_configuration.rb +17 -0
- data/examples/log_to_specific_account.rb +20 -0
- data/examples/update_campaign.rb +23 -0
- data/examples/update_campaign_name.rb +14 -0
- data/examples/update_campaign_status.rb +15 -0
- data/lib/adapi.rb +18 -0
- data/lib/adapi/ad.rb +64 -0
- data/lib/adapi/ad_group.rb +70 -0
- data/lib/adapi/ad_group_criterion.rb +68 -0
- data/lib/adapi/api.rb +20 -0
- data/lib/adapi/campaign.rb +142 -0
- data/lib/adapi/campaign_target.rb +90 -0
- data/lib/adapi/config.rb +54 -0
- data/lib/adapi/version.rb +3 -0
- data/lib/collection.rb +429 -0
- data/test/factories/.gitignore +0 -0
- data/test/test_helper.rb +20 -0
- data/test/unit/.gitignore +0 -0
- data/test/unit/campaign_target_test.rb +21 -0
- metadata +187 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'adapi'
|
2
|
+
|
3
|
+
# this example shows how to load custom settings
|
4
|
+
|
5
|
+
Adapi::Config.load_settings(
|
6
|
+
:path => File.expand_path(File.dirname(__FILE__)),
|
7
|
+
:filename => 'custom_settings.yml'
|
8
|
+
)
|
9
|
+
|
10
|
+
# :default account is set automatically
|
11
|
+
p "Default settings:"
|
12
|
+
p Adapi::Config.read[:authentication][:email]
|
13
|
+
|
14
|
+
Adapi::Config.set(:sandbox)
|
15
|
+
p "Set :sandbox account:"
|
16
|
+
p Adapi::Config.read[:authentication][:email]
|
17
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
require 'adapi'
|
3
|
+
|
4
|
+
# use specific config data
|
5
|
+
Adapi::Config.set({
|
6
|
+
:authentication => {
|
7
|
+
:method => 'ClientLogin',
|
8
|
+
:email => 'sandbox_email@gmail.com',
|
9
|
+
:password => 'sandbox_password',
|
10
|
+
:developer_token => 'sandbox_developer_token',
|
11
|
+
:client_email => 'sandbox_client_email@gmail.com',
|
12
|
+
:user_agent => 'Adwords API Test'
|
13
|
+
},
|
14
|
+
:service => {
|
15
|
+
:environment => 'SANDBOX'
|
16
|
+
}
|
17
|
+
})
|
18
|
+
|
19
|
+
# create campaign
|
20
|
+
require 'add_bare_campaign'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
require 'adapi'
|
3
|
+
|
4
|
+
# create campaign
|
5
|
+
require 'add_bare_campaign'
|
6
|
+
|
7
|
+
p 'original status: %s' % $campaign[:status]
|
8
|
+
|
9
|
+
campaign_updates = {
|
10
|
+
:id => $campaign[:id],
|
11
|
+
:status => 'ACTIVE'
|
12
|
+
}
|
13
|
+
|
14
|
+
$campaign = Adapi::Campaign.update(:data => campaign_updates)
|
15
|
+
|
16
|
+
p 'updated status: %s' % $campaign[:status]
|
17
|
+
|
18
|
+
$campaign = Adapi::Campaign.update(
|
19
|
+
:id => $campaign[:id],
|
20
|
+
:data => {:status => 'DELETED'}
|
21
|
+
)
|
22
|
+
|
23
|
+
p 'updated status (again): %s' % $campaign[:status]
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
require 'adapi'
|
3
|
+
|
4
|
+
# create campaign
|
5
|
+
require 'add_bare_campaign'
|
6
|
+
|
7
|
+
p 'original name: %s' % $campaign[:name]
|
8
|
+
|
9
|
+
$campaign = Adapi::Campaign.rename(
|
10
|
+
:id => $campaign[:id],
|
11
|
+
:name => "Renamed Campaign #%d" % (Time.new.to_f * 1000).to_i
|
12
|
+
)
|
13
|
+
|
14
|
+
p 'updated name: %s' % $campaign[:name]
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
require 'adapi'
|
3
|
+
|
4
|
+
# create campaign
|
5
|
+
require 'add_bare_campaign'
|
6
|
+
|
7
|
+
p 'original status: %s' % $campaign[:status]
|
8
|
+
|
9
|
+
$campaign = Adapi::Campaign.activate(:id => $campaign[:id])
|
10
|
+
|
11
|
+
p 'updated status: %s' % $campaign[:status]
|
12
|
+
|
13
|
+
$campaign = Adapi::Campaign.delete(:id => $campaign[:id])
|
14
|
+
|
15
|
+
p 'updated status (again): %s' % $campaign[:status]
|
data/lib/adapi.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'adwords_api'
|
4
|
+
require 'collection'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
require 'adapi/config'
|
8
|
+
require 'adapi/api'
|
9
|
+
require 'adapi/campaign'
|
10
|
+
require 'adapi/campaign_target'
|
11
|
+
require 'adapi/ad_group'
|
12
|
+
require 'adapi/ad_group_criterion'
|
13
|
+
require 'adapi/ad'
|
14
|
+
require 'adapi/version'
|
15
|
+
|
16
|
+
module Adapi
|
17
|
+
API_VERSION = :v201101
|
18
|
+
end
|
data/lib/adapi/ad.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Adapi
|
2
|
+
|
3
|
+
# TODO add synonym for actual service name: AdGroupAd
|
4
|
+
#
|
5
|
+
class Ad < Api
|
6
|
+
|
7
|
+
def initialize(params = {})
|
8
|
+
params[:service_name] = :AdGroupAdService
|
9
|
+
super(params)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.create(params = {})
|
13
|
+
ad_service = Ad.new
|
14
|
+
|
15
|
+
ad_group_id = params[:data].delete(:ad_group_id)
|
16
|
+
|
17
|
+
operation = { :operator => 'ADD',
|
18
|
+
:operand => { :ad_group_id => ad_group_id, :ad => params[:data] }
|
19
|
+
}
|
20
|
+
|
21
|
+
response = ad_service.service.mutate([operation])
|
22
|
+
|
23
|
+
ad_group = response[:value].first
|
24
|
+
|
25
|
+
ad = nil
|
26
|
+
if response and response[:value]
|
27
|
+
ad = response[:value].first
|
28
|
+
puts " Ad ID is #{ad[:ad][:id]}, type is '#{ad[:ad][:xsi_type]}' and status is '#{ad[:status]}'."
|
29
|
+
end
|
30
|
+
|
31
|
+
ad
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.find(params = {})
|
35
|
+
ad_service = Ad.new
|
36
|
+
|
37
|
+
raise "No AdGroup ID" unless params[:ad_group_id]
|
38
|
+
ad_group_id = params[:ad_group_id].to_i
|
39
|
+
|
40
|
+
selector = {
|
41
|
+
:fields => ['Id', 'Headline'],
|
42
|
+
:ordering => [{:field => 'Id', :sort_order => 'ASCENDING'}],
|
43
|
+
:predicates => [
|
44
|
+
{:field => 'AdGroupId', :operator => 'EQUALS', :values => ad_group_id }
|
45
|
+
# { :field => 'Status', :operator => 'IN', :values => ['ENABLED', 'PAUSED', 'DISABLED'] }
|
46
|
+
]
|
47
|
+
}
|
48
|
+
|
49
|
+
response = ad_service.service.get(selector)
|
50
|
+
|
51
|
+
if response and response[:entries]
|
52
|
+
ads = response[:entries]
|
53
|
+
puts "Ad group ##{ad_group_id} has #{ads.length} ad(s)."
|
54
|
+
ads.each do |ad|
|
55
|
+
puts " Ad id is #{ad[:ad][:id]}, type is #{ad[:ad][:xsi_type]} and " +
|
56
|
+
"status is \"#{ad[:status]}\"."
|
57
|
+
end
|
58
|
+
else
|
59
|
+
puts "No ads found for ad group ##{ad_group_id}."
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Adapi
|
2
|
+
class AdGroup < Api
|
3
|
+
|
4
|
+
def initialize(params = {})
|
5
|
+
params[:service_name] = :AdGroupService
|
6
|
+
super(params)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.create(params = {})
|
10
|
+
ad_group_service = AdGroup.new
|
11
|
+
|
12
|
+
criteria = params[:data].delete(:criteria)
|
13
|
+
ads = params[:data].delete(:ads) || []
|
14
|
+
|
15
|
+
# prepare for adding campaign
|
16
|
+
operation = { :operator => 'ADD', :operand => params[:data] }
|
17
|
+
|
18
|
+
response = ad_group_service.service.mutate([operation])
|
19
|
+
|
20
|
+
ad_group = response[:value].first
|
21
|
+
|
22
|
+
if criteria
|
23
|
+
Adapi::AdGroupCriterion.create(
|
24
|
+
:ad_group_id => ad_group[:id],
|
25
|
+
:criteria => criteria
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
ads.each do |ad_data|
|
30
|
+
Adapi::Ad.create(
|
31
|
+
:data => ad_data.merge(:ad_group_id => ad_group[:id])
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
# puts "Ad group ID %d was successfully added." % ad_group[:id]
|
36
|
+
ad_group
|
37
|
+
end
|
38
|
+
|
39
|
+
# should be sorted out later, but leave it be for now
|
40
|
+
#
|
41
|
+
def self.find(params = {})
|
42
|
+
ad_group_service = AdGroup.new
|
43
|
+
|
44
|
+
raise "No Campaign ID" unless params[:campaign_id]
|
45
|
+
campaign_id = params[:campaign_id]
|
46
|
+
|
47
|
+
selector = {
|
48
|
+
:fields => ['Id', 'Name'],
|
49
|
+
# :ordering => [{:field => 'Name', :sort_order => 'ASCENDING'}],
|
50
|
+
:predicates => [{
|
51
|
+
:field => 'CampaignId', :operator => 'EQUALS', :values => campaign_id
|
52
|
+
}]
|
53
|
+
}
|
54
|
+
|
55
|
+
response = ad_group_service.service.get(selector)
|
56
|
+
|
57
|
+
if response and response[:entries]
|
58
|
+
ad_groups = response[:entries]
|
59
|
+
puts "Campaign ##{campaign_id} has #{ad_groups.length} ad group(s)."
|
60
|
+
ad_groups.each do |ad_group|
|
61
|
+
puts " Ad group name is \"#{ad_group[:name]}\" and id is #{ad_group[:id]}."
|
62
|
+
end
|
63
|
+
else
|
64
|
+
puts "No ad groups found for campaign ##{campaign_id}."
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Adapi
|
2
|
+
class AdGroupCriterion < Api
|
3
|
+
|
4
|
+
def initialize(params = {})
|
5
|
+
params[:service_name] = :AdGroupCriterionService
|
6
|
+
super(params)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.create(params = {})
|
10
|
+
ad_group_criterion_service = AdGroupCriterion.new
|
11
|
+
|
12
|
+
raise "No criteria available" unless params[:criteria].is_a?(Array)
|
13
|
+
|
14
|
+
# if ad_group_id is supplied as separate parameter, include it into
|
15
|
+
# criteria
|
16
|
+
if params[:ad_group_id]
|
17
|
+
params[:criteria].map! { |c| c.merge(:ad_group_id => params[:ad_group_id].to_i) }
|
18
|
+
end
|
19
|
+
|
20
|
+
operation = params[:criteria].map do |criterion|
|
21
|
+
{ :operator => 'ADD', :operand => criterion }
|
22
|
+
end
|
23
|
+
|
24
|
+
response = ad_group_criterion_service.service.mutate(operation)
|
25
|
+
|
26
|
+
ad_group_criteria = nil
|
27
|
+
if response and response[:value]
|
28
|
+
ad_group_criteria = response[:value]
|
29
|
+
puts "Added #{ad_group_criteria.length} criteria " # "to ad group #{ad_group_id}."
|
30
|
+
ad_group_criteria.each do |ad_group_criterion|
|
31
|
+
puts " Criterion id is #{ad_group_criterion[:criterion][:id]} and " +
|
32
|
+
"type is #{ad_group_criterion[:criterion][:"@xsi:type"]}."
|
33
|
+
end
|
34
|
+
else
|
35
|
+
puts "No criteria were added."
|
36
|
+
end
|
37
|
+
|
38
|
+
ad_group_criteria
|
39
|
+
end
|
40
|
+
|
41
|
+
def find(params = {})
|
42
|
+
raise "No Campaign ID" unless params[:campaign_id]
|
43
|
+
campaign_id = params[:campaign_id]
|
44
|
+
|
45
|
+
selector = {
|
46
|
+
:fields => ['Id', 'Name'],
|
47
|
+
# :ordering => [{:field => 'Name', :sort_order => 'ASCENDING'}],
|
48
|
+
:predicates => [{
|
49
|
+
:field => 'CampaignId', :operator => 'EQUALS', :values => campaign_id
|
50
|
+
}]
|
51
|
+
}
|
52
|
+
|
53
|
+
response = @service.get(selector)
|
54
|
+
|
55
|
+
if response and response[:entries]
|
56
|
+
ad_groups = response[:entries]
|
57
|
+
puts "Campaign ##{campaign_id} has #{ad_groups.length} ad group(s)."
|
58
|
+
ad_groups.each do |ad_group|
|
59
|
+
puts " Ad group name is \"#{ad_group[:name]}\" and id is #{ad_group[:id]}."
|
60
|
+
end
|
61
|
+
else
|
62
|
+
puts "No ad groups found for campaign ##{campaign_id}."
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
data/lib/adapi/api.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Adapi
|
2
|
+
class Api
|
3
|
+
|
4
|
+
attr_accessor :adwords, :service, :version, :params
|
5
|
+
|
6
|
+
def initialize(params = {})
|
7
|
+
raise "Missing Service Name" unless params[:service_name]
|
8
|
+
|
9
|
+
puts "\n\nEXISTING INSTANCE USED\n\n" if params[:adwords_api_instance]
|
10
|
+
|
11
|
+
# if params[:api_login] in nil, default login data are used
|
12
|
+
# from ~/adwords_api.yml
|
13
|
+
@adwords = params[:adwords_api_instance] || AdwordsApi::Api.new(Adapi::Config.read)
|
14
|
+
@version = API_VERSION
|
15
|
+
@service = @adwords.service(params[:service_name].to_sym, @version)
|
16
|
+
@params = params
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Adapi
|
2
|
+
class Campaign < Api
|
3
|
+
|
4
|
+
def initialize(params = {})
|
5
|
+
params[:service_name] = :CampaignService
|
6
|
+
super(params)
|
7
|
+
end
|
8
|
+
|
9
|
+
# campaign data can be passed either as single hash:
|
10
|
+
# Campaign.create(:name => 'Campaign 123', :status => 'ENABLED')
|
11
|
+
# or as hash in a :data key:
|
12
|
+
# Campaign.create(:data => { :name => 'Campaign 123', :status => 'ENABLED' })
|
13
|
+
#
|
14
|
+
def self.create(params = {})
|
15
|
+
campaign_service = Campaign.new
|
16
|
+
|
17
|
+
# give users options to shorten input params
|
18
|
+
params = { :data => params } unless params.has_key?(:data)
|
19
|
+
|
20
|
+
# prepare for adding campaign
|
21
|
+
ad_groups = params[:data].delete(:ad_groups).to_a
|
22
|
+
targets = params[:data].delete(:targets)
|
23
|
+
|
24
|
+
operation = { :operator => 'ADD', :operand => params[:data] }
|
25
|
+
|
26
|
+
response = campaign_service.service.mutate([operation])
|
27
|
+
|
28
|
+
campaign = nil
|
29
|
+
if response and response[:value]
|
30
|
+
campaign = response[:value].first
|
31
|
+
puts "Campaign with name '%s' and ID %d was added." % [campaign[:name], campaign[:id]]
|
32
|
+
else
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
|
36
|
+
# create targets if they are available
|
37
|
+
if targets
|
38
|
+
Adapi::CampaignTarget.create(
|
39
|
+
:campaign_id => campaign[:id],
|
40
|
+
:targets => targets,
|
41
|
+
:api_adwords_instance => campaign_service.adwords
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
# if campaign has ad_groups, create them as well
|
46
|
+
ad_groups.each do |ad_group_data|
|
47
|
+
Adapi::AdGroup.create(
|
48
|
+
:data => ad_group_data.merge(:campaign_id => campaign[:id]),
|
49
|
+
:api_adwords_instance => campaign_service.adwords
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
campaign
|
54
|
+
end
|
55
|
+
|
56
|
+
# general method for changing campaign data
|
57
|
+
# TODO enable updating of all campaign parts at once, same as for Campaign#create method
|
58
|
+
#
|
59
|
+
def self.update(params = {})
|
60
|
+
campaign_service = Campaign.new
|
61
|
+
|
62
|
+
# give users options to shorten input params
|
63
|
+
params = { :data => params } unless params.has_key?(:data)
|
64
|
+
|
65
|
+
campaign_id = params[:id] || params[:data][:id] || nil
|
66
|
+
return nil unless campaign_id
|
67
|
+
|
68
|
+
operation = { :operator => 'SET',
|
69
|
+
:operand => params[:data].merge(:id => campaign_id.to_i)
|
70
|
+
}
|
71
|
+
|
72
|
+
response = campaign_service.service.mutate([operation])
|
73
|
+
|
74
|
+
if response and response[:value]
|
75
|
+
campaign = response[:value].first
|
76
|
+
puts 'Campaign id %d successfully updated.' % campaign[:id]
|
77
|
+
else
|
78
|
+
puts 'No campaigns were updated.'
|
79
|
+
end
|
80
|
+
|
81
|
+
return campaign
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.set_status(params = {})
|
85
|
+
params[:id] ||= (params[:data] || params[:data][:id]) || nil
|
86
|
+
return nil unless params[:id]
|
87
|
+
return nil unless %w{ ACTIVE PAUSED DELETED }.include?(params[:status])
|
88
|
+
|
89
|
+
self.update(:id => params[:id], :status => params[:status])
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.activate(params = {})
|
93
|
+
self.set_status params.merge(:status => 'ACTIVE')
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.pause(params = {})
|
97
|
+
self.set_status params.merge(:status => 'PAUSED')
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.delete(params = {})
|
101
|
+
self.set_status params.merge(:status => 'DELETED')
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.rename(params = {})
|
105
|
+
params[:id] ||= (params[:data] || params[:data][:id]) || nil
|
106
|
+
return nil unless (params[:id] && params[:name])
|
107
|
+
|
108
|
+
self.update(:id => params[:id], :name => params[:name])
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.find(params = {})
|
112
|
+
campaign_service = Campaign.new
|
113
|
+
|
114
|
+
selector = {
|
115
|
+
:fields => ['Id', 'Name', 'Status']
|
116
|
+
# :predicates => [{ :field => 'Id', :operator => 'EQUALS', :values => '334315' }]
|
117
|
+
# :ordering => [{:field => 'Name', :sort_order => 'ASCENDING'}]
|
118
|
+
}
|
119
|
+
|
120
|
+
# set filtering conditions: find by id, status etc.
|
121
|
+
if params[:conditions]
|
122
|
+
selector[:predicates] = params[:conditions].map do |c|
|
123
|
+
{ :field => c[0].to_s.capitalize, :operator => 'EQUALS', :values => c[1] }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
response = campaign_service.service.get(selector)
|
128
|
+
|
129
|
+
return (response and response[:entries]) ? response[:entries].to_a : []
|
130
|
+
|
131
|
+
if response
|
132
|
+
response[:entries].to_a.each do |campaign|
|
133
|
+
puts "Campaign name is \"#{campaign[:name]}\", id is #{campaign[:id]} " +
|
134
|
+
"and status is \"#{campaign[:status]}\"."
|
135
|
+
end
|
136
|
+
else
|
137
|
+
puts "No campaigns were found."
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|