jjp-openx 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,134 @@
1
+ require 'yaml'
2
+
3
+ module OpenX
4
+ module Services
5
+ class Base
6
+ include Comparable
7
+
8
+ # HOME || HOMEPATH is for Win32 users who do not have HOME set by default
9
+ #
10
+ # Configuration can be overridden for Rails at load time by doing this:
11
+ # OpenX::Services::Base.configuration =
12
+ # YAML.load_file(File.join(Rails.root, 'config', 'credentials.yml'))[Rails.env]
13
+ #
14
+ # Rescue nil is there for Rails sites that are monitored by Monit,
15
+ # which does not set the environment variables as expected.
16
+ # Note that the configuration can be set explicitly (as above),
17
+ # in which case this constant is not used and can safely be nil.
18
+ CONFIGURATION_YAML = File.join((ENV['HOME'] || ENV['HOMEPATH']), '.openx', 'credentials.yml') rescue nil
19
+
20
+ @@connection = nil
21
+ @@configuration = nil
22
+
23
+ class << self
24
+ attr_accessor :translations
25
+ attr_accessor :create, :update, :delete, :find_one, :find_all
26
+
27
+ def configuration
28
+ @@configuration ||=
29
+ YAML.load_file(CONFIGURATION_YAML)[ENV['OPENX_ENV'] || 'production']
30
+ end
31
+
32
+ def configuration=(c); @@configuration = c; end
33
+
34
+ def connection= c
35
+ @@connection = c
36
+ end
37
+
38
+ def connection
39
+ unless @@connection
40
+ @@connection = Session.new(configuration['url'])
41
+ @@connection.create( configuration['username'],
42
+ configuration['password']
43
+ )
44
+ end
45
+ @@connection
46
+ end
47
+
48
+ def create!(params = {})
49
+ new(params).save!
50
+ end
51
+
52
+ def openx_accessor(accessor_map)
53
+ @translations ||= {}
54
+ @translations = accessor_map.merge(@translations)
55
+ accessor_map.each do |ruby,openx|
56
+ attr_accessor :"#{ruby}"
57
+ end
58
+ end
59
+
60
+ def has_one(*things)
61
+ things.each do |thing|
62
+ attr_writer :"#{thing}"
63
+ define_method(:"#{thing}") do
64
+ klass = thing.to_s.capitalize.gsub(/_[a-z]/) { |m| m[1].chr.upcase }
65
+ klass = OpenX::Services.const_get(:"#{klass}")
66
+ klass.find(send("#{thing}_id"))
67
+ end
68
+ end
69
+ end
70
+
71
+ def find(id, *args)
72
+ session = self.connection
73
+ server = XmlrpcClient.new2("#{session.url}")
74
+ if id == :all
75
+ responses = server.call(find_all(), session, *args)
76
+ responses.map { |response|
77
+ new(translate(response))
78
+ }
79
+ else
80
+ response = server.call(find_one(), session, id)
81
+ new(translate(response))
82
+ end
83
+ end
84
+
85
+ def destroy(id)
86
+ new(:id => id).destroy
87
+ end
88
+
89
+ private
90
+ def translate(response)
91
+ params = {}
92
+ self.translations.each { |k,v|
93
+ params[k] = response[v.to_s] if response[v.to_s]
94
+ }
95
+ params
96
+ end
97
+ end
98
+
99
+ def initialize(params = {})
100
+ @id = nil
101
+ params.each { |k,v| send(:"#{k}=", v) }
102
+ @server = XmlrpcClient.new2("#{self.class.connection.url}")
103
+ end
104
+
105
+ def new_record?; @id.nil?; end
106
+
107
+ def save!
108
+ params = {}
109
+ session = self.class.connection
110
+ self.class.translations.keys.each { |k|
111
+ value = send(:"#{k}")
112
+ params[self.class.translations[k].to_s] = value if value
113
+ }
114
+
115
+ if new_record?
116
+ @id = @server.call(self.class.create, session, params)
117
+ else
118
+ @server.call(self.class.update, session, params)
119
+ end
120
+ self
121
+ end
122
+
123
+ def destroy
124
+ session = self.class.connection
125
+ @server.call(self.class.delete, session, id)
126
+ @id = nil
127
+ end
128
+
129
+ def <=>(other)
130
+ self.id <=> other.id
131
+ end
132
+ end
133
+ end
134
+ 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,8 @@
1
+ require 'openx/services/base'
2
+ require 'openx/services/session'
3
+ require 'openx/services/advertiser'
4
+ require 'openx/services/agency'
5
+ require 'openx/services/campaign'
6
+ require 'openx/services/banner'
7
+ require 'openx/services/publisher'
8
+ require 'openx/services/zone'
@@ -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
data/lib/openx.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'xmlrpc/client'
2
+ require 'openx/xmlrpc_client'
3
+ require 'openx/services'
4
+ require 'openx/invocation'
5
+ require 'openx/image'
6
+
7
+ module OpenX
8
+ VERSION = '1.1.0'
9
+ end
@@ -0,0 +1,110 @@
1
+ Index: www/api/v2/xmlrpc/BannerXmlRpcService.php
2
+ ===================================================================
3
+ --- www/api/v2/xmlrpc/BannerXmlRpcService.php (revision 44144)
4
+ +++ www/api/v2/xmlrpc/BannerXmlRpcService.php (working copy)
5
+ @@ -86,7 +86,7 @@
6
+ 1, array('campaignId', 'bannerName', 'storageType', 'fileName',
7
+ 'imageURL', 'htmlTemplate', 'width', 'height', 'weight',
8
+ 'target', 'url', 'bannerText', 'status', 'adserver', 'transparent',
9
+ - 'capping', 'sessionCapping', 'block', 'comments'),
10
+ + 'capping', 'sessionCapping', 'block', 'comments', 'keyword'),
11
+ array('aImage', 'aBackupImage'), $oResponseWithError)) {
12
+
13
+ return $oResponseWithError;
14
+ @@ -121,7 +121,7 @@
15
+ 1, array('bannerId', 'campaignId', 'bannerName', 'storageType', 'fileName',
16
+ 'imageURL', 'htmlTemplate', 'width', 'height', 'weight',
17
+ 'target', 'url', 'bannerText', 'status', 'adserver', 'transparent',
18
+ - 'capping', 'sessionCapping', 'block', 'comments'),
19
+ + 'capping', 'sessionCapping', 'block', 'comments', 'keyword'),
20
+ array('aImage', 'aBackupImage'), $oResponseWithError)) {
21
+
22
+ return $oResponseWithError;
23
+ Index: lib/OA/Dll/Banner.php
24
+ ===================================================================
25
+ --- lib/OA/Dll/Banner.php (revision 44144)
26
+ +++ lib/OA/Dll/Banner.php (working copy)
27
+ @@ -203,7 +203,8 @@
28
+ !$this->checkStructureNotRequiredIntegerField($oBanner, 'capping') ||
29
+ !$this->checkStructureNotRequiredIntegerField($oBanner, 'sessionCapping') ||
30
+ !$this->checkStructureNotRequiredIntegerField($oBanner, 'block') ||
31
+ - !$this->checkStructureNotRequiredStringField($oBanner, 'comments')
32
+ + !$this->checkStructureNotRequiredStringField($oBanner, 'comments') ||
33
+ + !$this->checkStructureNotRequiredStringField($oBanner, 'keyword')
34
+ ) {
35
+ return false;
36
+ }
37
+ Index: lib/OA/Dll/BannerInfo.php
38
+ ===================================================================
39
+ --- lib/OA/Dll/BannerInfo.php (revision 44144)
40
+ +++ lib/OA/Dll/BannerInfo.php (working copy)
41
+ @@ -210,6 +210,13 @@
42
+ var $comments;
43
+
44
+ /**
45
+ + * This field provides keywords to be stored.
46
+ + *
47
+ + * @var string $keyword
48
+ + */
49
+ + var $keyword;
50
+ +
51
+ + /**
52
+ * This method sets all default values when adding a new banner.
53
+ *
54
+ * @access public
55
+ @@ -251,6 +258,10 @@
56
+ if (is_null($this->block)) {
57
+ // Leave null
58
+ }
59
+ +
60
+ + if (is_null($this->keyword)) {
61
+ + // Leave null
62
+ + }
63
+ }
64
+
65
+ function encodeImage($aImage)
66
+ @@ -305,6 +316,7 @@
67
+ 'aImage' => 'custom',
68
+ 'aBackupImage' => 'custom',
69
+ 'comments' => 'string',
70
+ + 'keyword' => 'string',
71
+ );
72
+ }
73
+ }
74
+ Index: lib/xmlrpc/php/BannerInfo.php
75
+ ===================================================================
76
+ --- lib/xmlrpc/php/BannerInfo.php (revision 44144)
77
+ +++ lib/xmlrpc/php/BannerInfo.php (working copy)
78
+ @@ -210,6 +210,13 @@
79
+ var $comments;
80
+
81
+ /**
82
+ + * This field provides keywords to be stored.
83
+ + *
84
+ + * @var string $keyword
85
+ + */
86
+ + var $keyword;
87
+ +
88
+ + /**
89
+ * This method sets all default values when adding a new banner.
90
+ *
91
+ * @access public
92
+ @@ -251,6 +258,10 @@
93
+ if (is_null($this->block)) {
94
+ // Leave null
95
+ }
96
+ +
97
+ + if (is_null($this->keyword)) {
98
+ + // Leave null
99
+ + }
100
+ }
101
+
102
+ function encodeImage($aImage)
103
+ @@ -305,6 +316,7 @@
104
+ 'aImage' => 'custom',
105
+ 'aBackupImage' => 'custom',
106
+ 'comments' => 'string',
107
+ + 'keyword' => 'string',
108
+ );
109
+ }
110
+ }
Binary file
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