touchlocal-openx 1.1.0
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 +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
|