adapi 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|