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
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
== MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2011, Lukas Stejskal.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
== Adapi
|
2
|
+
|
3
|
+
Adapi (shortened "AdWords API") is a library for easy and painless work with
|
4
|
+
Google Adwords API. Its users shouldn't bother with SOAP and tangle of XML- and
|
5
|
+
API-specific objects (remember adwords4r gem?), inputs and outputs are plain
|
6
|
+
Ruby arrays and hashes.
|
7
|
+
|
8
|
+
Adapi is built on new Google Adwords API gems: google-ads-common and
|
9
|
+
google-adwords-api. Arrays and hashes instead of objects come from there, but
|
10
|
+
adapi takes it several steps further. AdWords services are represented by models
|
11
|
+
with relations, so among other things it's possible to create whole campaign in
|
12
|
+
single method call: Adapi::Campaign.create(campaign_data). Various convenience
|
13
|
+
methods are added to the models, for example: campaign.pause! (pauses
|
14
|
+
campaign). Adapi enables multiple AdWords accounts to be used at the same time.
|
15
|
+
|
16
|
+
Adapi is STILL IN DEVELOPMENT, not nearly done yet! Version 0.1.0 should have
|
17
|
+
all planned functionality.
|
18
|
+
|
19
|
+
== Installation
|
20
|
+
|
21
|
+
gem install adapi
|
22
|
+
|
23
|
+
=== from git repository
|
24
|
+
|
25
|
+
bundle install
|
26
|
+
rake install
|
27
|
+
|
28
|
+
== Configuration of AdWords Account(s)
|
29
|
+
|
30
|
+
This section explains how to connect to specific account and client.
|
31
|
+
|
32
|
+
In general, you can set many AdWords accounts to connect to (similarly as you
|
33
|
+
can set up several databases in Rails, for example).
|
34
|
+
|
35
|
+
=== Authentication workflow
|
36
|
+
|
37
|
+
* load configuration from ~/adapi.yml
|
38
|
+
* load configuration from ~/adwords_api.yml (default configuration for AdWords gems
|
39
|
+
from Google)
|
40
|
+
* set configuration directly to Adapi::Config (overrides previous settings)
|
41
|
+
|
42
|
+
=== Configuration by adapi.yml
|
43
|
+
|
44
|
+
Stored in ~/adapi.yml. Supports multiple accounts, which are identifed by
|
45
|
+
aliases. Example:
|
46
|
+
|
47
|
+
:default:
|
48
|
+
:authentication:
|
49
|
+
:method: ClientLogin
|
50
|
+
:email: default_email@gmail.com
|
51
|
+
:password: default_password
|
52
|
+
:developer_token: default_token
|
53
|
+
:client_email: default_client_email@gmail.com
|
54
|
+
:user_agent: My Adwords API Client
|
55
|
+
:service:
|
56
|
+
:environment: PRODUCTION
|
57
|
+
|
58
|
+
:sandbox:
|
59
|
+
:authentication:
|
60
|
+
:method: ClientLogin
|
61
|
+
:email: sandbox_email@gmail.com
|
62
|
+
:password: sandbox_password
|
63
|
+
:developer_token: sandbox_token
|
64
|
+
:client_email: sandbox_client_email@gmail.com
|
65
|
+
:user_agent: Adwords API Test
|
66
|
+
:service:
|
67
|
+
:environment: SANDBOX
|
68
|
+
|
69
|
+
You tell adapi which account to use by setting an alias:
|
70
|
+
|
71
|
+
Adapi::Config.set(:sandbox)
|
72
|
+
|
73
|
+
:default account is, as name implies, used by default. You must either set an
|
74
|
+
alias to Adapi::Config or have account with :default alias available.
|
75
|
+
|
76
|
+
=== Configuration by adwords_api.yml
|
77
|
+
|
78
|
+
If you already have google-adwords-api gem configured and use just one account,
|
79
|
+
the same configuration will also work for adapi: ~/adwords_api.yml
|
80
|
+
|
81
|
+
=== Configuration directly in code
|
82
|
+
|
83
|
+
Before logging into the Adwords API, you can set global settings through
|
84
|
+
Adapi::Config:
|
85
|
+
|
86
|
+
Adapi::Config.set({
|
87
|
+
:authentication:
|
88
|
+
:method: ClientLogin
|
89
|
+
:email: sandbox_email@gmail.com
|
90
|
+
:password: sandbox_password
|
91
|
+
:developer_token: sandbox_token
|
92
|
+
:client_email: sandbox_client_email@gmail.com
|
93
|
+
:user_agent: Adwords API Test
|
94
|
+
:service:
|
95
|
+
:environment: SANDBOX
|
96
|
+
})
|
97
|
+
|
98
|
+
This will override any previous configuration and set the account as :default.
|
99
|
+
You can specify more accounts this way, with aliases, in the same way as in
|
100
|
+
~/adapi.yml.
|
101
|
+
|
102
|
+
== API
|
103
|
+
|
104
|
+
There are two ways of working with API. Both examples show adding an ad to
|
105
|
+
specific campaign's ad group:
|
106
|
+
|
107
|
+
=== Model-centric
|
108
|
+
|
109
|
+
Adapi::Campaign.create(campaign_data)
|
110
|
+
|
111
|
+
=== TODO Collection-centric
|
112
|
+
|
113
|
+
account = Adapi::Account.new(:account_alias)
|
114
|
+
|
115
|
+
campaign = account.campaigns.create(campaign_data)
|
116
|
+
|
117
|
+
account.campaigns[ campaign[:id] ].ad_groups << ad_group_data
|
118
|
+
|
119
|
+
== Examples
|
120
|
+
|
121
|
+
Example are available in /examples directory. For now, they are mostly just dumb
|
122
|
+
rewrites of examples from google-adwords-api gem, but that's going to change
|
123
|
+
when proper UI to AdWords models will be implemented.
|
124
|
+
|
125
|
+
== Author
|
126
|
+
|
127
|
+
Lukas Stejskal
|
data/Rakefile
ADDED
data/adapi.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "adapi/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "adapi"
|
7
|
+
s.version = Adapi::VERSION
|
8
|
+
s.authors = ["Lukas Stejskal"]
|
9
|
+
s.email = ["lucastej@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{User-friendly interface to Google Adwords API}
|
12
|
+
s.description = %q{This gem provides user-friendly interface to Google Adwords API.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "adapi"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency "google-ads-common", "~> 0.5.1"
|
22
|
+
s.add_dependency "google-adwords-api", "~> 0.4.1"
|
23
|
+
|
24
|
+
s.add_development_dependency "turn"
|
25
|
+
s.add_development_dependency "shoulda"
|
26
|
+
s.add_development_dependency "fakeweb"
|
27
|
+
s.add_development_dependency "factory_girl"
|
28
|
+
end
|
data/examples/add_ad.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
require 'adapi'
|
3
|
+
|
4
|
+
# create ad group
|
5
|
+
require 'add_bare_ad_group'
|
6
|
+
|
7
|
+
ad_data = {
|
8
|
+
:ad_group_id => $ad_group[:id],
|
9
|
+
:xsi_type => 'TextAd',
|
10
|
+
:headline => "Code like Neo",
|
11
|
+
:description1 => 'Need mad coding skills?',
|
12
|
+
:description2 => 'Check out my new blog!',
|
13
|
+
:url => 'http://www.demcodez.com',
|
14
|
+
:display_url => 'http://www.demcodez.com'
|
15
|
+
}
|
16
|
+
|
17
|
+
p Adapi::Ad.create(:data => ad_data)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
require 'adapi'
|
3
|
+
|
4
|
+
# create campaign
|
5
|
+
require 'add_bare_campaign'
|
6
|
+
|
7
|
+
# create ad group
|
8
|
+
|
9
|
+
ad_group_data = {
|
10
|
+
:name => "AdGroup #%d" % (Time.new.to_f * 1000).to_i,
|
11
|
+
:status => 'ENABLED',
|
12
|
+
:campaign_id => $campaign[:id],
|
13
|
+
:bids => {
|
14
|
+
:xsi_type => 'ManualCPCAdGroupBids',
|
15
|
+
:keyword_max_cpc => {
|
16
|
+
:amount => {
|
17
|
+
:micro_amount => 10000000
|
18
|
+
}
|
19
|
+
}
|
20
|
+
},
|
21
|
+
|
22
|
+
:criteria => [
|
23
|
+
{ # keyword_criterion
|
24
|
+
:xsi_type => 'BiddableAdGroupCriterion',
|
25
|
+
:criterion => { :xsi_type => 'Keyword', :text => 'codez', :match_type => 'BROAD' }
|
26
|
+
},
|
27
|
+
{ # placement_criterion
|
28
|
+
:xsi_type => 'BiddableAdGroupCriterion',
|
29
|
+
:criterion => { :xsi_type => 'Placement', :url => 'http://www.blogger.com' }
|
30
|
+
}
|
31
|
+
],
|
32
|
+
|
33
|
+
:ads => [
|
34
|
+
{
|
35
|
+
:xsi_type => 'TextAd',
|
36
|
+
:headline => "Code like Neo",
|
37
|
+
:description1 => 'Need mad coding skills?',
|
38
|
+
:description2 => 'Check out my new blog!',
|
39
|
+
:url => 'http://www.demcodez.com',
|
40
|
+
:display_url => 'http://www.demcodez.com'
|
41
|
+
}
|
42
|
+
]
|
43
|
+
|
44
|
+
}
|
45
|
+
|
46
|
+
p Adapi::AdGroup.create(:data => ad_group_data)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
require 'adapi'
|
3
|
+
|
4
|
+
# create ad group
|
5
|
+
require 'add_bare_ad_group'
|
6
|
+
|
7
|
+
keyword_criterion = {
|
8
|
+
:xsi_type => 'BiddableAdGroupCriterion',
|
9
|
+
:criterion => { :xsi_type => 'Keyword', :text => 'codez', :match_type => 'BROAD' }
|
10
|
+
}
|
11
|
+
|
12
|
+
placement_criterion = {
|
13
|
+
:xsi_type => 'BiddableAdGroupCriterion',
|
14
|
+
:criterion => { :xsi_type => 'Placement', :url => 'http://www.blogger.com' }
|
15
|
+
}
|
16
|
+
|
17
|
+
p Adapi::AdGroupCriterion.create(
|
18
|
+
:ad_group_id => $ad_group[:id],
|
19
|
+
:criteria => [keyword_criterion, placement_criterion]
|
20
|
+
)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
require 'adapi'
|
3
|
+
|
4
|
+
# create campaign
|
5
|
+
require 'add_bare_campaign'
|
6
|
+
|
7
|
+
# create ad group with basic data only
|
8
|
+
# this script is used as an include in other scripts
|
9
|
+
|
10
|
+
$ad_group_data = {
|
11
|
+
:name => "AdGroup #%d" % (Time.new.to_f * 1000).to_i,
|
12
|
+
:status => 'ENABLED',
|
13
|
+
:campaign_id => $campaign[:id],
|
14
|
+
:bids => {
|
15
|
+
:xsi_type => 'ManualCPCAdGroupBids',
|
16
|
+
:keyword_max_cpc => {
|
17
|
+
:amount => {
|
18
|
+
:micro_amount => 10000000
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
$ad_group = Adapi::AdGroup.create(:data => $ad_group_data)
|
25
|
+
|
26
|
+
p $ad_group
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
require 'adapi'
|
3
|
+
|
4
|
+
# add campaign with basic data only
|
5
|
+
# this script is used as an include in other scripts
|
6
|
+
|
7
|
+
$campaign_data = {
|
8
|
+
:name => "Campaign #%d" % (Time.new.to_f * 1000).to_i,
|
9
|
+
:status => 'PAUSED',
|
10
|
+
:bidding_strategy => { :xsi_type => 'ManualCPC' },
|
11
|
+
:budget => {
|
12
|
+
:period => 'DAILY',
|
13
|
+
:amount => { :micro_amount => 50000000 },
|
14
|
+
:delivery_method => 'STANDARD'
|
15
|
+
},
|
16
|
+
|
17
|
+
:network_setting => {
|
18
|
+
:target_google_search => true,
|
19
|
+
:target_search_network => true,
|
20
|
+
:target_content_network => false,
|
21
|
+
:target_content_contextual => false
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
$campaign = Adapi::Campaign.create($campaign_data)
|
26
|
+
|
27
|
+
p $campaign
|
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
require 'adapi'
|
3
|
+
|
4
|
+
# create campaign by single command, with campaing targets, with ad_groups
|
5
|
+
# including keywords and ads
|
6
|
+
|
7
|
+
campaign_data = {
|
8
|
+
:name => "Campaign #%d" % (Time.new.to_f * 1000).to_i,
|
9
|
+
:status => 'PAUSED',
|
10
|
+
:bidding_strategy => { :xsi_type => 'ManualCPC' },
|
11
|
+
:budget => {
|
12
|
+
:period => 'DAILY',
|
13
|
+
:amount => { :micro_amount => 50000000 },
|
14
|
+
:delivery_method => 'STANDARD'
|
15
|
+
},
|
16
|
+
|
17
|
+
:network_setting => {
|
18
|
+
:target_google_search => true,
|
19
|
+
:target_search_network => true,
|
20
|
+
:target_content_network => false,
|
21
|
+
:target_content_contextual => false
|
22
|
+
},
|
23
|
+
|
24
|
+
:targets => {
|
25
|
+
:language => [ 'en', 'cs' ],
|
26
|
+
:geo => { :country => 'CZ' }
|
27
|
+
},
|
28
|
+
|
29
|
+
:ad_groups => [
|
30
|
+
{
|
31
|
+
:name => "AdGroup #%d" % (Time.new.to_f * 1000).to_i,
|
32
|
+
:status => 'ENABLED',
|
33
|
+
:bids => {
|
34
|
+
:xsi_type => 'ManualCPCAdGroupBids',
|
35
|
+
:keyword_max_cpc => {
|
36
|
+
:amount => {
|
37
|
+
:micro_amount => 10000000
|
38
|
+
}
|
39
|
+
}
|
40
|
+
},
|
41
|
+
|
42
|
+
:criteria => [
|
43
|
+
{ # keyword_criterion
|
44
|
+
:xsi_type => 'BiddableAdGroupCriterion',
|
45
|
+
:criterion => { :xsi_type => 'Keyword', :text => 'codez', :match_type => 'BROAD' }
|
46
|
+
},
|
47
|
+
{ # placement_criterion
|
48
|
+
:xsi_type => 'BiddableAdGroupCriterion',
|
49
|
+
:criterion => { :xsi_type => 'Placement', :url => 'http://www.blogger.com' }
|
50
|
+
}
|
51
|
+
],
|
52
|
+
|
53
|
+
:ads => [
|
54
|
+
{
|
55
|
+
:xsi_type => 'TextAd',
|
56
|
+
:headline => "Code like Neo",
|
57
|
+
:description1 => 'Need mad coding skills?',
|
58
|
+
:description2 => 'Check out my new blog!',
|
59
|
+
:url => 'http://www.demcodez.com',
|
60
|
+
:display_url => 'http://www.demcodez.com'
|
61
|
+
}
|
62
|
+
]
|
63
|
+
}
|
64
|
+
]
|
65
|
+
|
66
|
+
}
|
67
|
+
|
68
|
+
p Adapi::Campaign.create(campaign_data)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
require 'adapi'
|
3
|
+
|
4
|
+
# create campaign
|
5
|
+
require 'add_bare_campaign'
|
6
|
+
|
7
|
+
# create campaign targets
|
8
|
+
campaign_target_data = {
|
9
|
+
:campaign_id => $campaign[:id],
|
10
|
+
:targets => {
|
11
|
+
:language => [ 'en', 'cs' ],
|
12
|
+
:geo => { :country => 'CZ' }
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
p Adapi::CampaignTarget.create(campaign_target_data)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
:default:
|
3
|
+
:authentication:
|
4
|
+
:method: ClientLogin
|
5
|
+
:email: default_email@gmail.com
|
6
|
+
:password: default_password
|
7
|
+
:developer_token: default_token
|
8
|
+
:client_email: default_client_email@gmail.com
|
9
|
+
:user_agent: My Adwords API Client
|
10
|
+
:service:
|
11
|
+
:environment: PRODUCTION
|
12
|
+
|
13
|
+
:sandbox:
|
14
|
+
:authentication:
|
15
|
+
:method: ClientLogin
|
16
|
+
:email: sandbox_email@gmail.com
|
17
|
+
:password: sandbox_password
|
18
|
+
:developer_token: sandbox_token
|
19
|
+
:client_email: sandbox_client_email@gmail.com
|
20
|
+
:user_agent: Adwords API Test
|
21
|
+
:service:
|
22
|
+
:environment: SANDBOX
|