adapi 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,7 +13,7 @@ single method call: Adapi::Campaign.create(campaign_data). Various convenience
13
13
  methods are added to the models, for example: campaign.pause! (pauses
14
14
  campaign). Adapi enables multiple AdWords accounts to be used at the same time.
15
15
 
16
- Adapi is STILL IN DEVELOPMENT, not nearly done yet! Version 0.1.0 should have
16
+ Adapi is STILL IN DEVELOPMENT and not nearly done yet! Version 1.0.0 should have
17
17
  all planned functionality.
18
18
 
19
19
  == Installation
@@ -25,12 +25,50 @@ all planned functionality.
25
25
  bundle install
26
26
  rake install
27
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).
28
+ == Configuration
29
+
30
+ This section explains how to connect to specific AdWords account and client.
31
+
32
+ You can set many AdWords accounts to connect to and switch between while running
33
+ the application. You can even update single values of the settings on-the-fly.
34
+
35
+ # load the settings
36
+ Adapi::Config.load_settings(:in_hash => {
37
+ :coca_cola => {
38
+ :authentication => {
39
+ :method => 'ClientLogin',
40
+ :email => 'coca_cola_email@gmail.com',
41
+ :password => 'coca_cola_password',
42
+ :developer_token => 'coca_cola_developer_token',
43
+ :user_agent => 'Coca-Cola Adwords API Test'
44
+ },
45
+ :service => {
46
+ :environment => 'SANDBOX'
47
+ }
48
+ },
49
+ :pepsi => {
50
+ :authentication => {
51
+ :method => 'ClientLogin',
52
+ :email => 'pepsi_email@gmail.com',
53
+ :password => 'pepsi_password',
54
+ :developer_token => 'pepsi_developer_token',
55
+ :user_agent => 'Pepsi Adwords API Test'
56
+ },
57
+ :service => {
58
+ :environment => 'SANDBOX'
59
+ }
60
+ }
61
+ })
62
+
63
+ # set to pepsi and specific client
64
+ Adapi::Config.set(:pepsi, :client_customer_id => '555-666-7777')
65
+
66
+ # do some stuff here...
67
+
68
+ # set to coca-cola and another client
69
+ Adapi::Config.set(:coca_cola, :client_customer_id => '777-666-5555')
70
+
71
+ # do some stuff here...
34
72
 
35
73
  === Authentication workflow
36
74
 
@@ -83,38 +121,35 @@ the same configuration will also work for adapi: ~/adwords_api.yml
83
121
  Before logging into the Adwords API, you can set global settings through
84
122
  Adapi::Config:
85
123
 
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
124
+ # load the settings
125
+ Adapi::Config.load_settings(:in_hash => {
126
+ :sandbox => {
127
+ :authentication => {
128
+ :method => "ClientLogin"
129
+ :email => "sandbox_email@gmail.com",
130
+ :password => "sandbox_password",
131
+ :developer_token => "sandbox_token",
132
+ :client_email => "sandbox_client_email@gmail.com",
133
+ :user_agent => "Adwords API Test"
134
+ },
135
+ :service => {
136
+ :environment => "SANDBOX"
137
+ }
138
+ }
139
+ })
140
+
141
+ Adapi::Config.set(:sandbox)
142
+
143
+ == TODO API
144
+
145
+ AdWords Services are implemented as models, similar to ActiveRecord models of
146
+ database tables. They are built on ActiveModel.
147
+
148
+ == API Version Support
149
+
150
+ Adapi supports only the latest version of Google AdWords API: v201101. Older
151
+ versions will not be supported. v201101 and newer versions will still be
152
+ supported when new versions are released.
118
153
 
119
154
  == Examples
120
155
 
@@ -20,6 +20,10 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_dependency "google-ads-common", "~> 0.5.0"
22
22
  s.add_dependency "google-adwords-api", "~> 0.4.0"
23
+ s.add_dependency "activemodel", "~> 3.1.0" # , :require => "active_model"
24
+ s.add_dependency "activesupport", "~> 3.1.0" #, :require => "active_support"
25
+ s.add_dependency "rake", "~> 0.9.2"
26
+ s.add_dependency "curb", "~> 0.7.15"
23
27
 
24
28
  s.add_development_dependency "turn"
25
29
  s.add_development_dependency "shoulda"
@@ -2,7 +2,7 @@
2
2
  require 'adapi'
3
3
 
4
4
  # create campaign
5
- require 'add_bare_campaign'
5
+ require File.join(File.dirname(__FILE__), 'add_bare_campaign')
6
6
 
7
7
  # create ad group
8
8
 
@@ -10,29 +10,11 @@ ad_group_data = {
10
10
  :name => "AdGroup #%d" % (Time.new.to_f * 1000).to_i,
11
11
  :status => 'ENABLED',
12
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
13
 
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
- ],
14
+ :keywords => [ 'dem codez', '"top coder"', '[-code]' ],
32
15
 
33
16
  :ads => [
34
17
  {
35
- :xsi_type => 'TextAd',
36
18
  :headline => "Code like Neo",
37
19
  :description1 => 'Need mad coding skills?',
38
20
  :description2 => 'Check out my new blog!',
@@ -40,7 +22,9 @@ ad_group_data = {
40
22
  :display_url => 'http://www.demcodez.com'
41
23
  }
42
24
  ]
43
-
44
25
  }
45
26
 
46
- p Adapi::AdGroup.create(:data => ad_group_data)
27
+ $ad_group = Adapi::AdGroup.create(ad_group_data)
28
+
29
+ p "Created ad_group ID #{$ad_group.id} for campaign ID #{$ad_group.campaign_id}"
30
+ p $ad_group.attributes
@@ -2,18 +2,21 @@
2
2
  require 'adapi'
3
3
 
4
4
  # create campaign
5
- require 'add_bare_campaign'
5
+ require File.join(File.dirname(__FILE__), 'add_bare_campaign')
6
6
 
7
7
  # create ad group with basic data only
8
8
  # this script is used as an include in other scripts
9
9
 
10
10
  $ad_group_data = {
11
+ :campaign_id => $campaign[:id],
11
12
  :name => "AdGroup #%d" % (Time.new.to_f * 1000).to_i,
12
13
  :status => 'ENABLED',
13
- :campaign_id => $campaign[:id],
14
+ # TODO refactor AdGroup.bids DSL
14
15
  :bids => {
15
- :xsi_type => 'ManualCPCAdGroupBids',
16
- :keyword_max_cpc => {
16
+ # this should be set automatically, it's dependent on Campaign.bids
17
+ :xsi_type => 'BudgetOptimizerAdGroupBids',
18
+ # :keyword_max_cpc => 10
19
+ :proxy_keyword_max_cpc => {
17
20
  :amount => {
18
21
  :micro_amount => 10000000
19
22
  }
@@ -21,6 +24,8 @@ $ad_group_data = {
21
24
  }
22
25
  }
23
26
 
24
- $ad_group = Adapi::AdGroup.create(:data => $ad_group_data)
27
+ $ad_group = Adapi::AdGroup.create($ad_group_data)
28
+
25
29
 
26
- p $ad_group
30
+ p "Created ad_group ID #{$ad_group.id} for campaign ID #{$ad_group.campaign_id}"
31
+ p $ad_group.attributes
@@ -7,12 +7,9 @@ require 'adapi'
7
7
  $campaign_data = {
8
8
  :name => "Campaign #%d" % (Time.new.to_f * 1000).to_i,
9
9
  :status => 'PAUSED',
10
- :bidding_strategy => { :xsi_type => 'ManualCPC' },
11
- :budget => {
12
- :period => 'DAILY',
13
- :amount => { :micro_amount => 50000000 },
14
- :delivery_method => 'STANDARD'
15
- },
10
+ # :bidding_strategy => 'ManualCPC',
11
+ :bidding_strategy => { :xsi_type => 'BudgetOptimizer', :bid_ceiling => 55 },
12
+ :budget => 50,
16
13
 
17
14
  :network_setting => {
18
15
  :target_google_search => true,
@@ -24,4 +21,5 @@ $campaign_data = {
24
21
 
25
22
  $campaign = Adapi::Campaign.create($campaign_data)
26
23
 
27
- p $campaign
24
+ p "Created campaign ID #{$campaign.id}"
25
+ p $campaign.attributes
@@ -7,12 +7,9 @@ require 'adapi'
7
7
  campaign_data = {
8
8
  :name => "Campaign #%d" % (Time.new.to_f * 1000).to_i,
9
9
  :status => 'PAUSED',
10
- :bidding_strategy => { :xsi_type => 'ManualCPC' },
11
- :budget => {
12
- :period => 'DAILY',
13
- :amount => { :micro_amount => 50000000 },
14
- :delivery_method => 'STANDARD'
15
- },
10
+ # Automatic CPC: BudgetOptimizer or ManualCPC
11
+ :bidding_strategy => { :xsi_type => 'BudgetOptimizer', :bid_ceiling => 100 },
12
+ :budget => { :amount => 50, :delivery_method => 'STANDARD' },
16
13
 
17
14
  :network_setting => {
18
15
  :target_google_search => true,
@@ -23,36 +20,19 @@ campaign_data = {
23
20
 
24
21
  :targets => {
25
22
  :language => [ 'en', 'cs' ],
26
- :geo => { :country => 'CZ' }
23
+ # TODO test together with city target
24
+ :geo => { :proximity => { :geo_point => '38.89859,-77.035971', :radius => '10 km' } }
27
25
  },
28
26
 
29
27
  :ad_groups => [
30
28
  {
31
29
  :name => "AdGroup #%d" % (Time.new.to_f * 1000).to_i,
32
30
  :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
-
31
+
32
+ :keywords => [ 'dem codez', '"top coder"', "[-code]" ],
33
+
53
34
  :ads => [
54
35
  {
55
- :xsi_type => 'TextAd',
56
36
  :headline => "Code like Neo",
57
37
  :description1 => 'Need mad coding skills?',
58
38
  :description2 => 'Check out my new blog!',
@@ -65,4 +45,7 @@ campaign_data = {
65
45
 
66
46
  }
67
47
 
68
- p Adapi::Campaign.create(campaign_data)
48
+ $campaign = Adapi::Campaign.create(campaign_data)
49
+
50
+ p "Created campaign ID #{$campaign.id}"
51
+ p $campaign.attributes
@@ -2,15 +2,24 @@
2
2
  require 'adapi'
3
3
 
4
4
  # create campaign
5
- require 'add_bare_campaign'
5
+ require File.join(File.dirname(__FILE__), 'add_bare_campaign')
6
6
 
7
- # create campaign targets
8
- campaign_target_data = {
7
+ # TODO we should be able call it from campaign instance, for example:
8
+ # $campaign.set_targets(:language => [ 'en' ], ...)
9
+
10
+ $campaign_target = Adapi::CampaignTarget.new(
9
11
  :campaign_id => $campaign[:id],
10
12
  :targets => {
11
- :language => [ 'en', 'cs' ],
12
- :geo => { :country => 'CZ' }
13
+ :language => [ 'en' ],
14
+ :geo => {
15
+ # :country => 'CZ'
16
+ # :province => 'CZ-PR'
17
+ # :city => { :city_name => 'Prague', :province_code => 'CZ-PR', :country_code => 'CZ' }
18
+ :proximity => { :geo_point => '50.083333,14.366667', :radius => '50 km' }
19
+ }
13
20
  }
14
- }
21
+ )
22
+
23
+ $campaign_target.create
15
24
 
16
- p Adapi::CampaignTarget.create(campaign_target_data)
25
+ p $campaign_target.attributes
@@ -0,0 +1,35 @@
1
+
2
+ require 'adapi'
3
+
4
+ # create campaign
5
+ require File.join(File.dirname(__FILE__), '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
+
14
+ :keywords => [ 'dem codez', '"top coder"', '[-code]' ],
15
+
16
+ :ads => [
17
+ {
18
+ :headline => "Code like Neo",
19
+ :description1 => 'Need mad coding skills?',
20
+ :description2 => 'Check out my new blog!',
21
+ # this should throw an error
22
+ :url => 'http://www.demcodez.com THIS IS INVALID',
23
+ :display_url => 'http://www.demcodez.com'
24
+ }
25
+ ]
26
+ }
27
+
28
+ $ad_group = Adapi::AdGroup.create(ad_group_data)
29
+
30
+ if $ad_group.errors.empty?
31
+ p $ad_group.data
32
+ else
33
+ p "ERRORS:"
34
+ p $ad_group.errors.to_a
35
+ end
@@ -0,0 +1,30 @@
1
+
2
+ require 'adapi'
3
+
4
+ # PolicyViolations will appread only in production, not in sandbox
5
+ #
6
+ #Adapi::Config.load_settings
7
+ #Adapi::Config.set(:production_settings)
8
+ #
9
+ #pp "Running in #{Adapi::Config.read[:service][:environment]}"
10
+
11
+ # create ad group
12
+ require File.join(File.dirname(__FILE__), 'add_bare_ad_group')
13
+
14
+ $ad = Adapi::Ad::TextAd.create(
15
+ :ad_group_id => $ad_group[:id],
16
+ :headline => "Code a Blog",
17
+ :description1 => 'Need mad coding skill?',
18
+ :description2 => 'Check out my new blog!!!', # !!! - this is invalid
19
+ :url => 'http://www.demcodez.com',
20
+ :display_url => 'http://www.demcodez.com',
21
+ :status => 'PAUSED'
22
+ )
23
+
24
+ if $ad.errors.empty?
25
+ p "OK"
26
+ p $ad.data
27
+ else
28
+ p "ERROR"
29
+ p $ad.errors.messages
30
+ end
@@ -0,0 +1,14 @@
1
+
2
+ require 'adapi'
3
+
4
+ # create ad group
5
+ require File.join(File.dirname(__FILE__), 'add_bare_ad_group')
6
+
7
+ $keywords = Adapi::Keyword.new(
8
+ :ad_group_id => $ad_group[:id],
9
+ :keywords => [ 'dem codez', '"top coder"', '[-code]' ]
10
+ )
11
+
12
+ $r = $keywords.create
13
+
14
+ p $keywords
@@ -0,0 +1,23 @@
1
+
2
+ require 'adapi'
3
+
4
+ # create ad group
5
+ require File.join(File.dirname(__FILE__), 'add_bare_ad_group')
6
+
7
+ ad = Adapi::Ad::TextAd.create(
8
+ :ad_group_id => $ad_group[:id],
9
+ :headline => "Code like Neo",
10
+ :description1 => 'Need mad coding skills?',
11
+ :description2 => 'Check out my new blog!',
12
+ :url => 'http://www.demcodez.com',
13
+ :display_url => 'http://www.demcodez.com',
14
+ :status => 'PAUSED'
15
+ )
16
+
17
+ if ad
18
+ p "OK"
19
+ p ad.data
20
+ else
21
+ p "ERROR"
22
+ p ad.errors.messages
23
+ end