bsm-openx 1.9.1
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/Gemfile +7 -0
- data/Gemfile.lock +22 -0
- data/README.txt +85 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/bsm-openx.gemspec +92 -0
- data/lib/openx.rb +41 -0
- data/lib/openx/image.rb +22 -0
- data/lib/openx/invocation.rb +62 -0
- data/lib/openx/services.rb +32 -0
- data/lib/openx/services/advertiser.rb +31 -0
- data/lib/openx/services/agency.rb +34 -0
- data/lib/openx/services/banner.rb +94 -0
- data/lib/openx/services/base.rb +97 -0
- data/lib/openx/services/campaign.rb +52 -0
- data/lib/openx/services/channel.rb +42 -0
- data/lib/openx/services/persistance.rb +64 -0
- data/lib/openx/services/publisher.rb +36 -0
- data/lib/openx/services/session.rb +44 -0
- data/lib/openx/services/targeting_rule.rb +125 -0
- data/lib/openx/services/targeting_rules.rb +26 -0
- data/lib/openx/services/zone.rb +82 -0
- data/lib/openx/xmlrpc_client.rb +72 -0
- data/test/assets/300x250.jpg +0 -0
- data/test/assets/cat.swf +0 -0
- data/test/helper.rb +131 -0
- data/test/test_advertiser.rb +82 -0
- data/test/test_agency.rb +94 -0
- data/test/test_banner.rb +85 -0
- data/test/test_base.rb +40 -0
- data/test/test_campaign.rb +64 -0
- data/test/test_channel.rb +65 -0
- data/test/test_openx.rb +17 -0
- data/test/test_publisher.rb +69 -0
- data/test/test_services.rb +16 -0
- data/test/test_session.rb +42 -0
- data/test/test_targeting_rule.rb +86 -0
- data/test/test_targeting_rules.rb +13 -0
- data/test/test_zone.rb +101 -0
- metadata +122 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
module OpenX
|
2
|
+
module Services
|
3
|
+
class Agency < Base
|
4
|
+
# Translate our property names to OpenX property names
|
5
|
+
openx_accessor :name => :agencyName,
|
6
|
+
:contact_name => :contactName,
|
7
|
+
:email => :emailAddress,
|
8
|
+
:username => :username,
|
9
|
+
:password => :password,
|
10
|
+
:id => :agencyId,
|
11
|
+
:account_id => :accountId
|
12
|
+
|
13
|
+
self.create = 'ox.addAgency'
|
14
|
+
self.update = 'ox.modifyAgency'
|
15
|
+
self.delete = 'ox.deleteAgency'
|
16
|
+
self.find_one = 'ox.getAgency'
|
17
|
+
self.find_all = 'ox.getAgencyList'
|
18
|
+
|
19
|
+
def create_advertiser!(params = {})
|
20
|
+
Advertiser.create!(params.merge({
|
21
|
+
:agency => self,
|
22
|
+
}))
|
23
|
+
end
|
24
|
+
|
25
|
+
def advertisers
|
26
|
+
Advertiser.find(:all, self.id)
|
27
|
+
end
|
28
|
+
|
29
|
+
def publishers
|
30
|
+
Publisher.find(:all, self.id)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module OpenX
|
4
|
+
module Services
|
5
|
+
class Banner < Base
|
6
|
+
LOCAL_SQL = 'sql'
|
7
|
+
LOCAL_WEB = 'web'
|
8
|
+
EXTERNAL = 'url'
|
9
|
+
HTML = 'html'
|
10
|
+
TEXT = 'txt'
|
11
|
+
|
12
|
+
RUNNING = 0
|
13
|
+
PAUSED = 1
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def find(id, *args)
|
17
|
+
if id == :all
|
18
|
+
responses = remote.call(find_all, *args)
|
19
|
+
response = responses.first
|
20
|
+
return [] unless response
|
21
|
+
responses = [response]
|
22
|
+
|
23
|
+
### Annoying.. For some reason OpenX returns a linked list.
|
24
|
+
### Probably a bug....
|
25
|
+
while response.key?('aImage')
|
26
|
+
response = response.delete('aImage')
|
27
|
+
break unless response
|
28
|
+
responses << response
|
29
|
+
end
|
30
|
+
|
31
|
+
responses.map do |response|
|
32
|
+
new(translate(response))
|
33
|
+
end
|
34
|
+
else
|
35
|
+
response = remote.call(find_one, id)
|
36
|
+
new(translate(response))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Translate our property names to OpenX property names
|
42
|
+
openx_accessor :name => :bannerName,
|
43
|
+
:campaign_id => :campaignId,
|
44
|
+
:id => :bannerId,
|
45
|
+
:storage_type => :storageType,
|
46
|
+
:file_name => :fileName,
|
47
|
+
:image_url => :imageURL,
|
48
|
+
:html_template => :htmlTemplate,
|
49
|
+
:width => :width,
|
50
|
+
:height => :height,
|
51
|
+
:weight => :weight,
|
52
|
+
:target => :target,
|
53
|
+
:url => :url,
|
54
|
+
:status => :status,
|
55
|
+
:adserver => :adserver,
|
56
|
+
:transparent => :transparent,
|
57
|
+
:image => :aImage,
|
58
|
+
:backup_image => :aBackupImage,
|
59
|
+
# 'keyword' only supported by patched server
|
60
|
+
# as per https://developer.openx.org/jira/browse/OX-4779
|
61
|
+
# No averse effect when unsupported by server (returns nil)
|
62
|
+
:keyword => :keyword,
|
63
|
+
:comments => :comments
|
64
|
+
|
65
|
+
has_one :campaign
|
66
|
+
|
67
|
+
self.create = 'ox.addBanner'
|
68
|
+
self.update = 'ox.modifyBanner'
|
69
|
+
self.delete = 'ox.deleteBanner'
|
70
|
+
self.find_one = 'ox.getBanner'
|
71
|
+
self.find_all = 'ox.getBannerListByCampaignId'
|
72
|
+
|
73
|
+
def initialize(params = {})
|
74
|
+
raise ArgumentError.new("Missing campaign_id") unless params[:campaign_id] || params[:campaign]
|
75
|
+
params[:campaign_id] ||= params[:campaign].id
|
76
|
+
super(params)
|
77
|
+
end
|
78
|
+
|
79
|
+
def statistics start_on = Date.today, end_on = Date.today
|
80
|
+
remote.call('ox.bannerDailyStatistics', self.id, start_on, end_on)
|
81
|
+
end
|
82
|
+
|
83
|
+
def targeting
|
84
|
+
remote.call('ox.getBannerTargeting', self.id) do |line|
|
85
|
+
TargetingRule.instantiate(line)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def targeting=(rules)
|
90
|
+
remote.call('ox.setBannerTargeting', self.id, rules)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module OpenX
|
2
|
+
module Services
|
3
|
+
class Base
|
4
|
+
extend Persistance::ClassMethods
|
5
|
+
include Persistance::InstanceMethods
|
6
|
+
include Comparable
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_accessor :translations
|
10
|
+
attr_writer :connection
|
11
|
+
attr_accessor :create, :update, :delete, :find_one, :find_all
|
12
|
+
|
13
|
+
# Establishes a custom connection. Example:
|
14
|
+
#
|
15
|
+
# class MyBanner < OpenX::Services::Banner
|
16
|
+
# establish_connection 'url' => 'http://custom.host/openx', 'user' => 'admin', 'password' => 'password'
|
17
|
+
# end
|
18
|
+
def establish_connection(conn)
|
19
|
+
conn = OpenX::Services.establish_connection(conn) if conn.is_a?(Hash)
|
20
|
+
self.connection = conn
|
21
|
+
end
|
22
|
+
|
23
|
+
# Execute a block using a custom connection. Example:
|
24
|
+
# custom_conn = OpenX::Services.establish_connection({ ... })
|
25
|
+
#
|
26
|
+
# OpenX::Services::Agency.with_connection(custom_conn) do
|
27
|
+
# OpenX::Services::Agency.find(:all)
|
28
|
+
# end
|
29
|
+
def with_connection(temporary)
|
30
|
+
current = @connection
|
31
|
+
begin
|
32
|
+
establish_connection(temporary)
|
33
|
+
yield
|
34
|
+
ensure
|
35
|
+
establish_connection(current)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the current connection (session)
|
40
|
+
def connection
|
41
|
+
@connection = nil unless defined?(@connection)
|
42
|
+
@connection || OpenX::Services.default_connection
|
43
|
+
end
|
44
|
+
|
45
|
+
# Remote API proxy. Example:
|
46
|
+
#
|
47
|
+
# OpenX::Services::Agency.remote.call 'ox.addAgency', ...
|
48
|
+
def remote
|
49
|
+
connection.remote
|
50
|
+
end
|
51
|
+
|
52
|
+
def has_one(*things)
|
53
|
+
things.each do |thing|
|
54
|
+
attr_writer :"#{thing}"
|
55
|
+
define_method(:"#{thing}") do
|
56
|
+
klass = thing.to_s.capitalize.gsub(/_[a-z]/) { |m| m[1].chr.upcase }
|
57
|
+
klass = OpenX::Services.const_get(:"#{klass}")
|
58
|
+
klass.find(send("#{thing}_id"))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def openx_accessor(accessor_map)
|
64
|
+
@translations ||= {}
|
65
|
+
@translations = accessor_map.merge(@translations)
|
66
|
+
accessor_map.each do |ruby,openx|
|
67
|
+
attr_accessor :"#{ruby}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize(params = {})
|
73
|
+
@id = nil
|
74
|
+
params.each { |k,v| send(:"#{k}=", v) }
|
75
|
+
end
|
76
|
+
|
77
|
+
def new_record?
|
78
|
+
@id.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
def <=>(other)
|
82
|
+
self.id <=> other.id
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
def connection
|
88
|
+
self.class.connection
|
89
|
+
end
|
90
|
+
|
91
|
+
def remote
|
92
|
+
self.class.remote
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,52 @@
|
|
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
|
+
:comments => :comments
|
21
|
+
|
22
|
+
has_one :advertiser
|
23
|
+
|
24
|
+
self.create = 'ox.addCampaign'
|
25
|
+
self.update = 'ox.modifyCampaign'
|
26
|
+
self.delete = 'ox.deleteCampaign'
|
27
|
+
self.find_one = 'ox.getCampaign'
|
28
|
+
self.find_all = 'ox.getCampaignListByAdvertiserId'
|
29
|
+
|
30
|
+
# Revenue types
|
31
|
+
CPM = 1
|
32
|
+
CPC = 2
|
33
|
+
CPA = 3
|
34
|
+
MONTHLY_TENANCY = 4
|
35
|
+
|
36
|
+
# Campaign types
|
37
|
+
REMNANT = 1
|
38
|
+
HIGH = 2
|
39
|
+
EXCLUSIVE = 3
|
40
|
+
|
41
|
+
def initialize(params = {})
|
42
|
+
raise ArgumentError.new("Missing advertiser_id") unless params[:advertiser_id] || params[:advertiser]
|
43
|
+
params[:advertiser_id] ||= params[:advertiser].id
|
44
|
+
super(params)
|
45
|
+
end
|
46
|
+
|
47
|
+
def banners
|
48
|
+
Banner.find(:all, self.id)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module OpenX
|
2
|
+
module Services
|
3
|
+
class Channel < Base
|
4
|
+
|
5
|
+
openx_accessor :name => :channelName,
|
6
|
+
:id => :channelId,
|
7
|
+
:comments => :comments,
|
8
|
+
:description => :description,
|
9
|
+
:publisher_id => :websiteId,
|
10
|
+
:agency_id => :agencyId
|
11
|
+
|
12
|
+
has_one :publisher
|
13
|
+
|
14
|
+
self.create = 'ox.addChannel'
|
15
|
+
self.update = 'ox.modifyChannel'
|
16
|
+
self.delete = 'ox.deleteChannel'
|
17
|
+
self.find_one = 'ox.getChannel'
|
18
|
+
self.find_all = 'ox.getChannelListByWebsiteId'
|
19
|
+
|
20
|
+
def initialize(params = {})
|
21
|
+
raise "need publisher" unless params[:publisher_id] || params[:publisher]
|
22
|
+
params[:publisher_id] ||= params[:publisher].id
|
23
|
+
super(params)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Retrieves targeting from channel
|
27
|
+
def targeting
|
28
|
+
raise "Channel must be saved" if new_record?
|
29
|
+
remote.call("ox.getChannelTargeting", self.id).map do |line|
|
30
|
+
TargetingRule.instantiate(line)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Applied targeting to channel. See OpenX::Services::TargetingRules for details
|
35
|
+
def targeting=(rules)
|
36
|
+
raise "Channel must be saved" if new_record?
|
37
|
+
remote.call("ox.setChannelTargeting", self.id, rules)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module OpenX
|
2
|
+
module Services
|
3
|
+
module Persistance
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
def create!(params = {})
|
8
|
+
new(params).save!
|
9
|
+
end
|
10
|
+
|
11
|
+
def find(id, *args)
|
12
|
+
if id == :all
|
13
|
+
responses = remote.call(find_all, *args)
|
14
|
+
responses.map do |response|
|
15
|
+
new(translate(response))
|
16
|
+
end
|
17
|
+
else
|
18
|
+
response = remote.call(find_one, id)
|
19
|
+
new(translate(response))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def destroy(id)
|
24
|
+
new(:id => id).destroy
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def translate(response)
|
30
|
+
params = {}
|
31
|
+
self.translations.each do |k,v|
|
32
|
+
params[k] = response[v.to_s] if response[v.to_s]
|
33
|
+
end
|
34
|
+
params
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
module InstanceMethods
|
40
|
+
|
41
|
+
def save!
|
42
|
+
params = {}
|
43
|
+
self.class.translations.keys.each do |k|
|
44
|
+
value = send(:"#{k}")
|
45
|
+
params[self.class.translations[k].to_s] = value if value
|
46
|
+
end
|
47
|
+
|
48
|
+
if new_record?
|
49
|
+
@id = remote.call(self.class.create, params)
|
50
|
+
else
|
51
|
+
remote.call(self.class.update, params)
|
52
|
+
end
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
def destroy
|
57
|
+
remote.call(self.class.delete, id)
|
58
|
+
@id = nil
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,36 @@
|
|
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
|
+
:website => :website
|
12
|
+
|
13
|
+
has_one :agency
|
14
|
+
|
15
|
+
self.create = 'ox.addPublisher'
|
16
|
+
self.update = 'ox.modifyPublisher'
|
17
|
+
self.delete = 'ox.deletePublisher'
|
18
|
+
self.find_one = 'ox.getPublisher'
|
19
|
+
self.find_all = 'ox.getPublisherListByAgencyId'
|
20
|
+
|
21
|
+
def initialize(params = {})
|
22
|
+
raise "need agency" unless params[:agency_id] || params[:agency]
|
23
|
+
params[:agency_id] ||= params[:agency].id
|
24
|
+
super(params)
|
25
|
+
end
|
26
|
+
|
27
|
+
def zones
|
28
|
+
Zone.find(:all, self.id)
|
29
|
+
end
|
30
|
+
|
31
|
+
def channels
|
32
|
+
Channel.find(:all, self.id)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module OpenX
|
2
|
+
module Services
|
3
|
+
class Session
|
4
|
+
attr_accessor :id, :uri, :user, :password
|
5
|
+
|
6
|
+
def initialize(url)
|
7
|
+
@uri = URI.parse(url)
|
8
|
+
@client = XmlrpcClient.new(self.url)
|
9
|
+
@id = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def url
|
13
|
+
uri.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def host
|
17
|
+
url.sub(/#{Regexp.escape(uri.path)}$/, '')
|
18
|
+
end
|
19
|
+
|
20
|
+
def remote
|
21
|
+
@remote ||= XmlrpcSessionClient.new(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def create(user, password)
|
25
|
+
self.user = user
|
26
|
+
self.password = password
|
27
|
+
self.id = @client.call('ox.logon', user, password)
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def recreate!
|
32
|
+
raise "Unable to refresh Session" unless user && password
|
33
|
+
self.id = @client.call('ox.logon', user, password)
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def destroy
|
38
|
+
@client.call('ox.logoff', id)
|
39
|
+
self.id = nil
|
40
|
+
self
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|