touchlocal-openx 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/History.txt +6 -0
- data/Manifest.txt +26 -0
- data/README.txt +109 -0
- data/Rakefile +40 -0
- data/VERSION +1 -0
- data/lib/openx.rb +9 -0
- data/lib/openx/image.rb +22 -0
- data/lib/openx/invocation.rb +63 -0
- data/lib/openx/services.rb +8 -0
- data/lib/openx/services/advertiser.rb +31 -0
- data/lib/openx/services/agency.rb +34 -0
- data/lib/openx/services/banner.rb +96 -0
- data/lib/openx/services/base.rb +124 -0
- data/lib/openx/services/campaign.rb +51 -0
- data/lib/openx/services/publisher.rb +31 -0
- data/lib/openx/services/session.rb +33 -0
- data/lib/openx/services/zone.rb +98 -0
- data/lib/openx/xmlrpc_client.rb +78 -0
- data/test/assets/300x250.jpg +0 -0
- data/test/assets/cat.swf +0 -0
- data/test/helper.rb +99 -0
- data/test/test_advertiser.rb +82 -0
- data/test/test_agency.rb +94 -0
- data/test/test_banner.rb +82 -0
- data/test/test_base.rb +37 -0
- data/test/test_campaign.rb +64 -0
- data/test/test_publisher.rb +69 -0
- data/test/test_session.rb +24 -0
- data/test/test_zone.rb +100 -0
- data/touchlocal-openx.gemspec +77 -0
- metadata +95 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module OpenX
|
4
|
+
module Services
|
5
|
+
class Base
|
6
|
+
include Comparable
|
7
|
+
|
8
|
+
CONFIGURATION_YAML = File.join(ENV['HOME'], '.openx', 'credentials.yml')
|
9
|
+
|
10
|
+
@@connection = nil
|
11
|
+
@@configuration = nil
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_accessor :translations
|
15
|
+
attr_accessor :create, :update, :delete, :find_one, :find_all
|
16
|
+
|
17
|
+
def configuration
|
18
|
+
@@configuration ||=
|
19
|
+
YAML.load_file(CONFIGURATION_YAML)[ENV['OPENX_ENV'] || 'production']
|
20
|
+
end
|
21
|
+
|
22
|
+
def configuration=(c); @@configuration = c; end
|
23
|
+
|
24
|
+
def connection= c
|
25
|
+
@@connection = c
|
26
|
+
end
|
27
|
+
|
28
|
+
def connection
|
29
|
+
unless @@connection
|
30
|
+
@@connection = Session.new(configuration['url'])
|
31
|
+
@@connection.create( configuration['username'],
|
32
|
+
configuration['password']
|
33
|
+
)
|
34
|
+
end
|
35
|
+
@@connection
|
36
|
+
end
|
37
|
+
|
38
|
+
def create!(params = {})
|
39
|
+
new(params).save!
|
40
|
+
end
|
41
|
+
|
42
|
+
def openx_accessor(accessor_map)
|
43
|
+
@translations ||= {}
|
44
|
+
@translations = accessor_map.merge(@translations)
|
45
|
+
accessor_map.each do |ruby,openx|
|
46
|
+
attr_accessor :"#{ruby}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def has_one(*things)
|
51
|
+
things.each do |thing|
|
52
|
+
attr_writer :"#{thing}"
|
53
|
+
define_method(:"#{thing}") do
|
54
|
+
klass = thing.to_s.capitalize.gsub(/_[a-z]/) { |m| m[1].chr.upcase }
|
55
|
+
klass = OpenX::Services.const_get(:"#{klass}")
|
56
|
+
klass.find(send("#{thing}_id"))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def find(id, *args)
|
62
|
+
session = self.connection
|
63
|
+
server = XmlrpcClient.new2("#{session.url}")
|
64
|
+
if id == :all
|
65
|
+
responses = server.call(find_all(), session, *args)
|
66
|
+
responses.map { |response|
|
67
|
+
new(translate(response))
|
68
|
+
}
|
69
|
+
else
|
70
|
+
response = server.call(find_one(), session, id)
|
71
|
+
new(translate(response))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def destroy(id)
|
76
|
+
new(:id => id).destroy
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
def translate(response)
|
81
|
+
params = {}
|
82
|
+
self.translations.each { |k,v|
|
83
|
+
params[k] = response[v.to_s] if response[v.to_s]
|
84
|
+
}
|
85
|
+
params
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def initialize(params = {})
|
90
|
+
@id = nil
|
91
|
+
params.each { |k,v| send(:"#{k}=", v) }
|
92
|
+
@server = XmlrpcClient.new2("#{self.class.connection.url}")
|
93
|
+
end
|
94
|
+
|
95
|
+
def new_record?; @id.nil?; end
|
96
|
+
|
97
|
+
def save!
|
98
|
+
params = {}
|
99
|
+
session = self.class.connection
|
100
|
+
self.class.translations.keys.each { |k|
|
101
|
+
value = send(:"#{k}")
|
102
|
+
params[self.class.translations[k].to_s] = value if value
|
103
|
+
}
|
104
|
+
|
105
|
+
if new_record?
|
106
|
+
@id = @server.call(self.class.create, session, params)
|
107
|
+
else
|
108
|
+
@server.call(self.class.update, session, params)
|
109
|
+
end
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
113
|
+
def destroy
|
114
|
+
session = self.class.connection
|
115
|
+
@server.call(self.class.delete, session, id)
|
116
|
+
@id = nil
|
117
|
+
end
|
118
|
+
|
119
|
+
def <=>(other)
|
120
|
+
self.id <=> other.id
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module OpenX
|
2
|
+
module Services
|
3
|
+
class Campaign < Base
|
4
|
+
# Translate our property names to OpenX property names
|
5
|
+
openx_accessor :name => :campaignName,
|
6
|
+
:advertiser_id => :advertiserId,
|
7
|
+
:id => :campaignId,
|
8
|
+
:start_date => :startDate,
|
9
|
+
:end_date => :endDate,
|
10
|
+
:impressions => :impressions,
|
11
|
+
:target_impressions => :targetImpressions,
|
12
|
+
:target_clicks => :targetClicks,
|
13
|
+
:revenue => :revenue,
|
14
|
+
:revenue_type => :revenueType,
|
15
|
+
:impressions => :impressions,
|
16
|
+
:clicks => :clicks,
|
17
|
+
:priority => :priority,
|
18
|
+
:weight => :weight,
|
19
|
+
:campaign_type => :campaignType
|
20
|
+
|
21
|
+
has_one :advertiser
|
22
|
+
|
23
|
+
self.create = 'ox.addCampaign'
|
24
|
+
self.update = 'ox.modifyCampaign'
|
25
|
+
self.delete = 'ox.deleteCampaign'
|
26
|
+
self.find_one = 'ox.getCampaign'
|
27
|
+
self.find_all = 'ox.getCampaignListByAdvertiserId'
|
28
|
+
|
29
|
+
# Revenue types
|
30
|
+
CPM = 1
|
31
|
+
CPC = 2
|
32
|
+
CPA = 3
|
33
|
+
MONTHLY_TENANCY = 4
|
34
|
+
|
35
|
+
# Campaign types
|
36
|
+
REMNANT = 1
|
37
|
+
HIGH = 2
|
38
|
+
EXCLUSIVE = 3
|
39
|
+
|
40
|
+
def initialize(params = {})
|
41
|
+
raise ArgumentError.new("Missing advertiser_id") unless params[:advertiser_id] || params[:advertiser]
|
42
|
+
params[:advertiser_id] ||= params[:advertiser].id
|
43
|
+
super(params)
|
44
|
+
end
|
45
|
+
|
46
|
+
def banners
|
47
|
+
Banner.find(:all, self.id)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module OpenX
|
2
|
+
module Services
|
3
|
+
class Publisher < Base
|
4
|
+
openx_accessor :name => :publisherName,
|
5
|
+
:contact_name => :contactName,
|
6
|
+
:email => :emailAddress,
|
7
|
+
:username => :username,
|
8
|
+
:password => :password,
|
9
|
+
:id => :publisherId,
|
10
|
+
:agency_id => :agencyId
|
11
|
+
|
12
|
+
has_one :agency
|
13
|
+
|
14
|
+
self.create = 'ox.addPublisher'
|
15
|
+
self.update = 'ox.modifyPublisher'
|
16
|
+
self.delete = 'ox.deletePublisher'
|
17
|
+
self.find_one = 'ox.getPublisher'
|
18
|
+
self.find_all = 'ox.getPublisherListByAgencyId'
|
19
|
+
|
20
|
+
def initialize(params = {})
|
21
|
+
raise "need agency" unless params[:agency_id] || params[:agency]
|
22
|
+
params[:agency_id] ||= params[:agency].id
|
23
|
+
super(params)
|
24
|
+
end
|
25
|
+
|
26
|
+
def zones
|
27
|
+
Zone.find(:all, self.id)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module OpenX
|
2
|
+
module Services
|
3
|
+
class Session
|
4
|
+
attr_accessor :url, :id
|
5
|
+
attr_accessor :user, :password
|
6
|
+
|
7
|
+
def initialize(url)
|
8
|
+
@url = url
|
9
|
+
@server = XmlrpcClient.new2("#{@url}")
|
10
|
+
@id = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def create(user, password)
|
14
|
+
@user = user
|
15
|
+
@password = password
|
16
|
+
@id = @server.call('ox.logon', @user, @password)
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def recreate!
|
21
|
+
raise "Unable to refresh Session" unless @user && @password
|
22
|
+
@id = @server.call('ox.logon', @user, @password)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def destroy
|
27
|
+
@server.call('ox.logoff', @id)
|
28
|
+
@id = nil
|
29
|
+
self
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module OpenX
|
2
|
+
module Services
|
3
|
+
class Zone < Base
|
4
|
+
# Delivery types
|
5
|
+
BANNER = 'delivery-b'
|
6
|
+
INTERSTITIAL = 'delivery-i'
|
7
|
+
TEXT = 'delivery-t'
|
8
|
+
EMAIL = 'delivery-e'
|
9
|
+
|
10
|
+
# Tag Types
|
11
|
+
JAVASCRIPT = 'adjs'
|
12
|
+
LOCAL = 'local'
|
13
|
+
IFRAME = 'adframe'
|
14
|
+
XMLRPC_TAG = 'xmlrpc'
|
15
|
+
|
16
|
+
openx_accessor :name => :zoneName,
|
17
|
+
:id => :zoneId,
|
18
|
+
:width => :width,
|
19
|
+
:height => :height,
|
20
|
+
:type => :type,
|
21
|
+
:publisher_id => :publisherId
|
22
|
+
|
23
|
+
has_one :publisher
|
24
|
+
|
25
|
+
self.create = 'ox.addZone'
|
26
|
+
self.update = 'ox.modifyZone'
|
27
|
+
self.delete = 'ox.deleteZone'
|
28
|
+
self.find_one = 'ox.getZone'
|
29
|
+
self.find_all = 'ox.getZoneListByPublisherId'
|
30
|
+
|
31
|
+
class << self
|
32
|
+
###
|
33
|
+
# Deliver +zone_id+ to +ip_address+ with +cookies+,
|
34
|
+
def deliver zone_id, ip_address = '192.168.1.1', cookies = []
|
35
|
+
url = "#{self.configuration['root']}/delivery/axmlrpc.php"
|
36
|
+
server = XmlrpcClient.new2(url)
|
37
|
+
server.call('openads.view', {
|
38
|
+
'cookies' => cookies,
|
39
|
+
'remote_addr' => ip_address,
|
40
|
+
}, "zone:#{zone_id}", 0, '', '', true, [])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(params = {})
|
45
|
+
raise "need publisher" unless params[:publisher_id] || params[:publisher]
|
46
|
+
params[:publisher_id] ||= params[:publisher].id
|
47
|
+
super(params)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Link this zone to +campaign+
|
51
|
+
def link_campaign(campaign)
|
52
|
+
raise "Zone must be saved" if new_record?
|
53
|
+
raise ArgumentError.new("Campaign must be saved")if campaign.new_record?
|
54
|
+
|
55
|
+
session = self.class.connection
|
56
|
+
server = XmlrpcClient.new2("#{session.url}")
|
57
|
+
server.call("ox.linkCampaign", session, self.id, campaign.id)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Unlink this zone from +campaign+
|
61
|
+
def unlink_campaign(campaign)
|
62
|
+
raise "Zone must be saved" if new_record?
|
63
|
+
raise ArgumentError.new("Campaign must be saved")if campaign.new_record?
|
64
|
+
|
65
|
+
session = self.class.connection
|
66
|
+
server = XmlrpcClient.new2("#{session.url}")
|
67
|
+
server.call("ox.unlinkCampaign", session, self.id, campaign.id)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Link this zone to +banner+
|
71
|
+
def link_banner(banner)
|
72
|
+
raise "Zone must be saved" if new_record?
|
73
|
+
raise ArgumentError.new("Banner must be saved")if banner.new_record?
|
74
|
+
|
75
|
+
session = self.class.connection
|
76
|
+
server = XmlrpcClient.new2("#{session.url}")
|
77
|
+
server.call("ox.linkBanner", session, self.id, banner.id)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Unlink this zone from +banner+
|
81
|
+
def unlink_banner(banner)
|
82
|
+
raise "Zone must be saved" if new_record?
|
83
|
+
raise ArgumentError.new("Banner must be saved")if banner.new_record?
|
84
|
+
|
85
|
+
session = self.class.connection
|
86
|
+
server = XmlrpcClient.new2("#{session.url}")
|
87
|
+
server.call("ox.unlinkBanner", session, self.id, banner.id)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Generate tags for displaying this zone using +tag_type+
|
91
|
+
def generate_tags(tag_type = IFRAME)
|
92
|
+
session = self.class.connection
|
93
|
+
server = XmlrpcClient.new2("#{session.url}")
|
94
|
+
server.call("ox.generateTags", session, self.id, tag_type, [])
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'xmlrpc/client'
|
2
|
+
|
3
|
+
module OpenX
|
4
|
+
|
5
|
+
unless defined? HTTPBroken
|
6
|
+
# A module that captures all the possible Net::HTTP exceptions
|
7
|
+
# from http://pastie.org/pastes/145154
|
8
|
+
module HTTPBroken; end
|
9
|
+
|
10
|
+
[Timeout::Error, Errno::EINVAL, Errno::EPIPE, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse,
|
11
|
+
Net::HTTPHeaderSyntaxError, Net::ProtocolError].each {|m| m.send(:include, HTTPBroken)}
|
12
|
+
end
|
13
|
+
|
14
|
+
class XmlrpcClient
|
15
|
+
@uri = nil
|
16
|
+
@server = nil
|
17
|
+
|
18
|
+
@retry_on_http_error = true
|
19
|
+
@timeout = 10 # seconds
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_accessor :retry_on_http_error, :timeout
|
23
|
+
|
24
|
+
def init_server(uri)
|
25
|
+
server = XMLRPC::Client.new2(uri)
|
26
|
+
server.timeout = self.timeout
|
27
|
+
#server.instance_variable_get(:@http).set_debug_output($stderr)
|
28
|
+
server
|
29
|
+
end
|
30
|
+
|
31
|
+
def new2(uri)
|
32
|
+
server = init_server(uri)
|
33
|
+
new(server, uri)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(server, uri)
|
38
|
+
@server = server
|
39
|
+
@uri = uri
|
40
|
+
end
|
41
|
+
|
42
|
+
def call(method, *args)
|
43
|
+
if args.first.is_a?(OpenX::Services::Session)
|
44
|
+
session = args.shift()
|
45
|
+
args.unshift(session.id)
|
46
|
+
begin
|
47
|
+
do_call(method, *args)
|
48
|
+
rescue XMLRPC::FaultException => sess_id_err
|
49
|
+
if sess_id_err.message.strip == 'Session ID is invalid'
|
50
|
+
session.recreate!
|
51
|
+
args.shift()
|
52
|
+
args.unshift(session.id)
|
53
|
+
do_call(method, *args)
|
54
|
+
else
|
55
|
+
raise sess_id_err
|
56
|
+
end
|
57
|
+
end
|
58
|
+
else
|
59
|
+
do_call(method, *args)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def do_call(method, *args)
|
64
|
+
begin
|
65
|
+
@server.call(method, *args)
|
66
|
+
rescue HTTPBroken => httpbe
|
67
|
+
if self.class.retry_on_http_error
|
68
|
+
@server = self.class.init_server(@uri)
|
69
|
+
@server.call(method, *args)
|
70
|
+
else
|
71
|
+
raise httpbe
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
private :do_call
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
Binary file
|
data/test/assets/cat.swf
ADDED
Binary file
|
data/test/helper.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '../lib')))
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'openx'
|
5
|
+
|
6
|
+
ENV['OPENX_ENV'] = 'test'
|
7
|
+
|
8
|
+
module OpenX
|
9
|
+
class TestCase < Test::Unit::TestCase
|
10
|
+
TEST_SWF = File.expand_path(File.join(File.dirname(__FILE__), 'assets', 'cat.swf'))
|
11
|
+
TEST_JPG = File.expand_path(File.join(File.dirname(__FILE__), 'assets', '300x250.jpg'))
|
12
|
+
|
13
|
+
include OpenX::Services
|
14
|
+
|
15
|
+
undef :default_test
|
16
|
+
|
17
|
+
def setup
|
18
|
+
assert(
|
19
|
+
File.exists?(Base::CONFIGURATION_YAML),
|
20
|
+
'Please create the credentials file'
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def agency
|
25
|
+
@agency ||= Agency.create!(
|
26
|
+
{
|
27
|
+
:name => "Testing! - #{Time.now}",
|
28
|
+
:contact_name => 'Contact Name!',
|
29
|
+
:email => 'foo@bar.com'
|
30
|
+
}
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def advertiser
|
35
|
+
@advertiser ||= Advertiser.create!(
|
36
|
+
{
|
37
|
+
:name => "adv-#{Time.now}",
|
38
|
+
:contact_name => 'Contact Name!',
|
39
|
+
:email => 'foo@bar.com'
|
40
|
+
}.merge(:agency => agency)
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
def campaign
|
45
|
+
@campaign ||= Campaign.create!(
|
46
|
+
{
|
47
|
+
:advertiser => advertiser,
|
48
|
+
:name => "Campaign-#{Time.now}",
|
49
|
+
:impressions => 2000
|
50
|
+
}
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def publisher
|
55
|
+
@publisher ||= Publisher.create!(
|
56
|
+
{
|
57
|
+
:agency => agency,
|
58
|
+
:name => "Publisher! - #{Time.now}",
|
59
|
+
:contact_name => 'Aaron Patterson',
|
60
|
+
:email => 'aaron@tenderlovemaking.com',
|
61
|
+
:username => 'one',
|
62
|
+
:password => 'two',
|
63
|
+
}
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
def zone
|
68
|
+
@zone ||= Zone.create!(
|
69
|
+
{
|
70
|
+
:publisher => publisher,
|
71
|
+
:name => "Zone - #{Time.now}",
|
72
|
+
:type => Zone::BANNER,
|
73
|
+
:width => 300,
|
74
|
+
:height => 250,
|
75
|
+
}
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
def banner
|
80
|
+
@banner ||= Banner.create!({
|
81
|
+
:name => "Banner-#{Time.now}",
|
82
|
+
:storage_type => Banner::LOCAL_SQL,
|
83
|
+
:campaign => campaign,
|
84
|
+
:url => 'http://tenderlovemaking.com/',
|
85
|
+
:file_name => 'oogabooga',
|
86
|
+
:image => OpenX::Image.new(File.open(TEST_SWF, 'rb'))
|
87
|
+
})
|
88
|
+
end
|
89
|
+
|
90
|
+
def destroy
|
91
|
+
@banner.destroy if defined? @banner
|
92
|
+
@zone.destroy if defined? @zone
|
93
|
+
@publisher.destroy if defined? @publisher
|
94
|
+
@campaign.destroy if defined? @campaign
|
95
|
+
@advertiser.destroy if defined? @advertiser
|
96
|
+
@agency.destroy if defined? @agency
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|