hasoffers 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ = HasOffers CHANGELOG
2
+
3
+ == Version 0.1.0
4
+
5
+ Initial framework including support for the following API calls:
6
+ * Advertiser: find_all, create, update
7
+ * Affiliate: create, update
8
+ * AffiliateBilling: find_invoice_stats, find_all_invoices, create_invoice, update_invoice
9
+ * Conversion: create, update
10
+ * Offer: create, update
11
+ * Report: get_stats
@@ -0,0 +1,23 @@
1
+ CHANGELOG
2
+ README.rdoc
3
+ Rakefile
4
+ config/has_offers.yml
5
+ lib/has_offers_model.rb
6
+ lib/hasoffers.rb
7
+ lib/hasoffers/advertiser.rb
8
+ lib/hasoffers/affiliate.rb
9
+ lib/hasoffers/affiliate_billing.rb
10
+ lib/hasoffers/base.rb
11
+ lib/hasoffers/conversion.rb
12
+ lib/hasoffers/dummy_response.rb
13
+ lib/hasoffers/offer.rb
14
+ lib/hasoffers/report.rb
15
+ lib/hasoffers/response.rb
16
+ test/advertiser_test.rb
17
+ test/affiliate_billing_test.rb
18
+ test/affiliate_test.rb
19
+ test/conversion_test.rb
20
+ test/offer_test.rb
21
+ test/report_test.rb
22
+ test/test_helper.rb
23
+ Manifest
@@ -0,0 +1,31 @@
1
+ == HasOffers
2
+
3
+ This gem hooks into the HasOffers API as documented here: http://www.hasoffers.com/wiki/Category:API
4
+
5
+ == Install
6
+
7
+ gem install ngin-hasoffers --source http://gems.github.com
8
+
9
+ == Usage
10
+
11
+ Add a has_offers.yml file to your RAILS_ROOT/config/ directory following the format outlined in the gems config/has_offers.yml file and change the credentials accordingly.
12
+
13
+ Example usage: (more examples in tests)
14
+ response = HasOffers::Offer.create('name' => 'Test',
15
+ 'description' => 'Test',
16
+ 'advertiser_id' => '1',
17
+ 'offer_url' => 'test',
18
+ 'preview_url' => 'test',
19
+ 'protocol' => 'https',
20
+ 'status' => 'active',
21
+ 'expiration_date' => (Date.today + 30).to_s)
22
+
23
+ The tests can be ran in two modes:
24
+
25
+ 1. Test mode: rake test
26
+ * Does not make real API calls. Dummy responses are returned by the DummyResponse class which is also useful in development mode to avoid real API calls
27
+
28
+ 2. Live mode: env REMOTE_TEST=1 rake test
29
+ * Makes real api calls. Uses the HasOffer credentials in config/has_offers.yml which by default is set to the demo account credentials. HasOffers does not supply a test gateway so be careful to not run these tests against your live HasOffers account.
30
+
31
+ The HasOffers API is huge and this gem implements only a portion of what is available with their API. With this framework in place it should be easy to extend the gem to support API calls that are not yet supported. Please send contributions as git patches.
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('hasoffers', '0.1.0') do |p|
6
+ p.description = "Implementation of the HasOffers API for affiliate advertising."
7
+ p.url = "http://github.com/ngin/hasoffers"
8
+ p.author = "Luke Ludwig"
9
+ p.email = "luke.ludwig@tstmedia.com"
10
+ p.development_dependencies = []
11
+ p.runtime_dependencies = ["yajl-ruby >= 0.7.6", "crack >= 0.1.6"]
12
+ end
13
+
14
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
@@ -0,0 +1,2 @@
1
+ api_key: "NEThSQ1Ah92G8f7JYqQuO5hnsULkia"
2
+ network_id: "demo"
@@ -0,0 +1,37 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{hasoffers}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Luke Ludwig"]
9
+ s.date = %q{2010-07-13}
10
+ s.description = %q{Implementation of the HasOffers API for affiliate advertising.}
11
+ s.email = %q{luke.ludwig@tstmedia.com}
12
+ s.extra_rdoc_files = ["CHANGELOG", "README.rdoc", "lib/has_offers_model.rb", "lib/hasoffers.rb", "lib/hasoffers/advertiser.rb", "lib/hasoffers/affiliate.rb", "lib/hasoffers/affiliate_billing.rb", "lib/hasoffers/base.rb", "lib/hasoffers/conversion.rb", "lib/hasoffers/dummy_response.rb", "lib/hasoffers/offer.rb", "lib/hasoffers/report.rb", "lib/hasoffers/response.rb"]
13
+ s.files = ["CHANGELOG", "README.rdoc", "Rakefile", "config/has_offers.yml", "lib/has_offers_model.rb", "lib/hasoffers.rb", "lib/hasoffers/advertiser.rb", "lib/hasoffers/affiliate.rb", "lib/hasoffers/affiliate_billing.rb", "lib/hasoffers/base.rb", "lib/hasoffers/conversion.rb", "lib/hasoffers/dummy_response.rb", "lib/hasoffers/offer.rb", "lib/hasoffers/report.rb", "lib/hasoffers/response.rb", "test/advertiser_test.rb", "test/affiliate_billing_test.rb", "test/affiliate_test.rb", "test/conversion_test.rb", "test/offer_test.rb", "test/report_test.rb", "test/test_helper.rb", "Manifest", "hasoffers.gemspec"]
14
+ s.homepage = %q{http://github.com/ngin/hasoffers}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Hasoffers", "--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{hasoffers}
18
+ s.rubygems_version = %q{1.3.5}
19
+ s.summary = %q{Implementation of the HasOffers API for affiliate advertising.}
20
+ s.test_files = ["test/advertiser_test.rb", "test/affiliate_billing_test.rb", "test/affiliate_test.rb", "test/conversion_test.rb", "test/offer_test.rb", "test/report_test.rb", "test/test_helper.rb"]
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<yajl-ruby>, [">= 0", "= 0.7.6"])
28
+ s.add_runtime_dependency(%q<crack>, [">= 0", "= 0.1.6"])
29
+ else
30
+ s.add_dependency(%q<yajl-ruby>, [">= 0", "= 0.7.6"])
31
+ s.add_dependency(%q<crack>, [">= 0", "= 0.1.6"])
32
+ end
33
+ else
34
+ s.add_dependency(%q<yajl-ruby>, [">= 0", "= 0.7.6"])
35
+ s.add_dependency(%q<crack>, [">= 0", "= 0.1.6"])
36
+ end
37
+ end
@@ -0,0 +1,55 @@
1
+ module HasOffersModel
2
+
3
+ def self.included(klass)
4
+ klass.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+
9
+ # requires that your model has the column has_offer_id
10
+ # requires that you implement the method has_offers_params within your model
11
+ def has_offers_model(has_offers_class_name)
12
+
13
+ has_offers_class = "HasOffers::#{has_offers_class_name}".constantize
14
+
15
+ class_eval do
16
+
17
+ define_method("has_offers_create") do
18
+ if respond_to? :has_offer_id
19
+ response = has_offers_class.create(has_offers_params)
20
+ if response.success?
21
+ if response.data.is_a? Hash
22
+ # return_object is true
23
+ self.has_offer_id = response.data[has_offers_class_name]["id"].to_i
24
+ else
25
+ # return_object is false
26
+ self.has_offer_id = response.data.to_i
27
+ end
28
+ end
29
+ check_for_errors(response)
30
+ end
31
+ end
32
+
33
+ define_method("has_offers_update") do
34
+ if respond_to?(:has_offer_id) and has_offer_id
35
+ response = has_offers_class.update(has_offer_id, has_offers_params)
36
+ check_for_errors(response)
37
+ end
38
+ end
39
+
40
+ define_method("check_for_errors") do |response|
41
+ unless response.success?
42
+ response.error_messages.each do |error_message|
43
+ self.errors.add_to_base "HasOffers API Error: #{error_message}"
44
+ end
45
+ end
46
+ response.success?
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,16 @@
1
+ require 'yaml'
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'yajl'
5
+ require 'crack'
6
+
7
+ # loading base classes which other models depend on
8
+ directory = File.expand_path(File.dirname(__FILE__))
9
+ require File.join(directory, "hasoffers", "response")
10
+ require File.join(directory, "hasoffers", "dummy_response")
11
+ require File.join(directory, "hasoffers", "base")
12
+
13
+ # loading all other models within hasoffers directory
14
+ Dir[File.dirname(__FILE__) + '/hasoffers/*.rb'].each do |f|
15
+ require f
16
+ end
@@ -0,0 +1,29 @@
1
+ module HasOffers
2
+
3
+ class Advertiser < Base
4
+
5
+ Target = 'Advertiser'
6
+
7
+ class << self
8
+
9
+ def find_all(params = {})
10
+ get_request(Target, 'findAll', params)
11
+ end
12
+
13
+ def create(data, return_object = false)
14
+ requires!(data, %w[company address1 city country zipcode phone])
15
+ params = build_data(data, return_object)
16
+ post_request(Target, 'create', params)
17
+ end
18
+
19
+ def update(id, data, return_object = false)
20
+ params = build_data(data, return_object)
21
+ params['id'] = id
22
+ post_request(Target, 'update', params)
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,28 @@
1
+ module HasOffers
2
+
3
+ class Affiliate < Base
4
+
5
+ Target = 'Affiliate'
6
+
7
+ class << self
8
+
9
+ def create(data, return_object = false)
10
+ requires!(data, %w[company address1 city country zipcode phone])
11
+ if data['country'] == 'US' or data['country'] == 'CA'
12
+ requires!(data, 'region')
13
+ end
14
+ params = build_data(data, return_object)
15
+ post_request(Target, 'create', params)
16
+ end
17
+
18
+ def update(id, data, return_object = false)
19
+ params = build_data(data, return_object)
20
+ params['id'] = id
21
+ post_request(Target, 'update', params)
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,42 @@
1
+ module HasOffers
2
+
3
+ class AffiliateBilling < Base
4
+
5
+ Target = 'AffiliateBilling'
6
+
7
+ class << self
8
+
9
+ def find_invoice_stats(params)
10
+ requires!(params, %w[affiliate_id end_date])
11
+ get_request(Target, 'findInvoiceStats', params)
12
+ end
13
+
14
+ def find_all_invoices(params)
15
+ response = get_request(Target, 'findAllInvoices', params)
16
+ if response.success?
17
+ # strip out the clutter
18
+ data = response.data.map do |invoice|
19
+ invoice[1].values.first
20
+ end
21
+ response.set_data data
22
+ end
23
+ response
24
+ end
25
+
26
+ def create_invoice(data, return_object = false)
27
+ requires!(data, %w[affiliate_id start_date end_date status])
28
+ params = build_data(data, return_object)
29
+ post_request(Target, 'createInvoice', params)
30
+ end
31
+
32
+ def update_invoice(id, data, return_object = false)
33
+ params = build_data(data, return_object)
34
+ params['id'] = id
35
+ post_request(Target, 'updateInvoice', params)
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,110 @@
1
+
2
+ module HasOffers
3
+
4
+ class Base
5
+
6
+ BaseUri = 'https://api.hasoffers.com/Api'
7
+ @@api_mode = (ENV['RAILS_ENV'] == 'production' or ENV['REMOTE_TEST'] == '1') ? :live : :test
8
+ @@default_params = nil
9
+
10
+ class << self
11
+
12
+ def initialize_credentials
13
+ config_file = ENV['HAS_OFFERS_CONFIG_FILE'] || "config/has_offers.yml"
14
+ if File.exists?(config_file)
15
+ config = YAML::load(IO.read(config_file))
16
+ @@default_params = {'Format' => 'json',
17
+ 'Service' => 'HasOffers',
18
+ 'Version' => '2',
19
+ 'NetworkId' => config['network_id'],
20
+ 'NetworkToken' => config['api_key']}
21
+ else
22
+ puts "Missing config/has_offers.yml file!"
23
+ end
24
+ end
25
+
26
+ def test?
27
+ @@api_mode == :test
28
+ end
29
+
30
+ def live?
31
+ @@api_mode == :live
32
+ end
33
+
34
+ def set_api_mode(mode)
35
+ @@api_mode = mode
36
+ end
37
+
38
+ def api_mode
39
+ @@api_mode
40
+ end
41
+
42
+ def get_request(target, method, params)
43
+ make_request(:get, target, method, params)
44
+ end
45
+
46
+ def post_request(target, method, params)
47
+ make_request(:post, target, method, params)
48
+ end
49
+
50
+ def requires!(hash, required_params)
51
+ missing_params = []
52
+ required_params.each do |param|
53
+ missing_params.push param unless hash.has_key?(param)
54
+ end
55
+ unless missing_params.empty?
56
+ raise ArgumentError.new("Missing required parameter(s): #{missing_params.join(', ')}")
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def new_http(uri)
63
+ http = Net::HTTP.new(uri.host, uri.port)
64
+ http.use_ssl = true
65
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
66
+ http
67
+ end
68
+
69
+ def query_string(data_hash)
70
+ # Rails to_params adds an extra open close brackets to multi-dimensional array parameters which
71
+ # hasoffers doesn't like, so the gsub here takes care of that.
72
+ data_hash.to_params.gsub(/\[\]\[/,'[')
73
+ end
74
+
75
+ def make_request(http_method, target, method, params)
76
+ data = build_request_params(target, method, params)
77
+ if live?
78
+ if http_method == :post
79
+ uri = URI.parse BaseUri
80
+ http = new_http uri
81
+ raw_request = Net::HTTP::Post.new(uri.request_uri)
82
+ raw_request.body = query_string data
83
+ else # assume get
84
+ uri = URI.parse("#{BaseUri}?#{query_string(data)}")
85
+ http = new_http uri
86
+ raw_request = Net::HTTP::Get.new(uri.request_uri)
87
+ end
88
+ http_response = http.request raw_request
89
+ else
90
+ http_response = DummyResponse.response_for(target, method, params)
91
+ end
92
+ Response.new(http_response)
93
+ end
94
+
95
+ def build_request_params(target, method, params)
96
+ initialize_credentials unless @@default_params
97
+ params['Target'] = target
98
+ params['Method'] = method
99
+ params.merge @@default_params
100
+ end
101
+
102
+ def build_data(data, return_object = false)
103
+ {'data' => data, 'return_object' => return_object}
104
+ end
105
+
106
+ end
107
+
108
+ end
109
+
110
+ end
@@ -0,0 +1,27 @@
1
+ module HasOffers
2
+
3
+ class Conversion < Base
4
+
5
+ Target = 'Conversion'
6
+
7
+ class << self
8
+
9
+ # number is number of conversions to create. Defaults to 1 on has offers side
10
+ def create(data, number = nil)
11
+ requires!(data, %w[affiliate_id offer_id payout revenue])
12
+ params = build_data data
13
+ params['number'] = number if number
14
+ post_request(Target, 'create', params)
15
+ end
16
+
17
+ def update(id, data, return_object = false)
18
+ params = build_data(data, return_object)
19
+ params['id'] = id
20
+ post_request(Target, 'update', params)
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,86 @@
1
+ module HasOffers
2
+
3
+ class DummyResponse
4
+
5
+ class << self
6
+
7
+ def response_for(target, method, params)
8
+ body = self.send("response_for_#{target.downcase}_#{method.downcase}", params)
9
+ DummyResponse.new(200, 'Ok', body, {})
10
+ end
11
+
12
+ # Assume return_object is set for simplicity which means just the id of offer is returned
13
+ def response_for_offer_create(params)
14
+ {"response" => { "status" => 1, "data" => rand(1_000_000).to_s } }
15
+ end
16
+
17
+ def response_for_offer_update(params)
18
+ {"response" => { "status" => 1, "data" => true, "errors" => [] } }
19
+ end
20
+
21
+ def response_for_affiliate_create(params)
22
+ {"response" => { "status" => 1, "data" => rand(1_000_000).to_s } }
23
+ end
24
+
25
+ def response_for_affiliate_update(params)
26
+ {"response" => { "status" => 1, "data" => true, "errors" => [] } }
27
+ end
28
+
29
+ def response_for_affiliatebilling_createinvoice(params)
30
+ {"response" => { "status" => 1, "data" => rand(1_000_000).to_s } }
31
+ end
32
+
33
+ def response_for_affiliatebilling_updateinvoice(params)
34
+ {"response" => { "status" => 1, "data" => true, "errors" => [] } }
35
+ end
36
+
37
+ def response_for_advertiser_findall(params)
38
+ {"response" => { "status" => 1, "data" => {"1" => {"Advertiser" => {"id" => "1", "company" => "Dominoes"}}}, "errors" => {} } }
39
+ end
40
+
41
+ def response_for_advertiser_create(params)
42
+ {"response" => { "status" => 1, "data" => rand(1_000_000).to_s } }
43
+ end
44
+
45
+ def response_for_advertiser_update(params)
46
+ {"response" => { "status" => 1, "data" => true, "errors" => [] } }
47
+ end
48
+
49
+ def response_for_conversion_create(params)
50
+ {"response" => { "status" => 1, "data" => rand(1_000_000).to_s } }
51
+ end
52
+
53
+ def response_for_conversion_update(params)
54
+ {"response" => { "status" => 1, "data" => true, "errors" => [] } }
55
+ end
56
+
57
+ def response_for_affiliatebilling_findinvoicestats(params)
58
+ {"response" => { "status" => 1, "data" => {"start_date" => params["start_date"], "end_date" => params["end_date"], "data" => [{"Stat" => {"type" => "stats", "offer_id" => "1", "payout_type" => "cpa_flat", "currency" => "USD", "amount" => "26.00000", "impressions" => "0", "clicks" => "0", "conversions" => "5", "revenue" => "2.50", "sale_amount" => "50.00"}}] }}}
59
+ end
60
+
61
+ def response_for_affiliatebilling_findallinvoices(params)
62
+ {"response" => { "status" => 1, "data" => {"1" => {"AffiliateInvoice" => {"id" => "1", "affiliate_id" => "2", "datetime" => "2009-06-02 20:14:05", "start_date" => "2009-06-01", "end_date" => "2009-06-02", "is_paid" => "1", "memo" => "asdf", "status" => "active", "notes" => "", "receipt_id" => nil, "currency" => "USD", "amount" => "12.00", "conversions" => "12" }}}, "errors" => []}}
63
+ end
64
+
65
+ def response_for_report_getstats(params)
66
+ {"response"=>{"data"=>{"pageCount"=>1, "data"=>[{"Stat"=>{"affiliate_id"=>"1", "clicks"=>"20645"}}], "current"=>50, "count"=>1, "page"=>1}, "errors"=>[], "status"=>1}}
67
+ end
68
+
69
+ end
70
+
71
+ attr_accessor :code, :message, :body, :headers
72
+
73
+ def initialize(code, message, body, headers)
74
+ @code = code
75
+ @message = message
76
+ @body = body
77
+ @headers = headers
78
+ end
79
+
80
+ def to_hash
81
+ @headers
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -0,0 +1,25 @@
1
+ module HasOffers
2
+
3
+ class Offer < Base
4
+
5
+ Target = 'Offer'
6
+
7
+ class << self
8
+
9
+ def create(data, return_object = false)
10
+ requires!(data, %w[name description advertiser_id offer_url preview_url protocol status expiration_date])
11
+ params = build_data data, return_object
12
+ post_request(Target, 'create', params)
13
+ end
14
+
15
+ def update(id, data, return_object = false)
16
+ params = build_data data, return_object
17
+ params['id'] = id
18
+ post_request(Target, 'update', params)
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,26 @@
1
+ module HasOffers
2
+
3
+ class Report < Base
4
+
5
+ Target = 'Report'
6
+
7
+ class << self
8
+
9
+ def get_stats(params)
10
+ requires!(params, %w[fields])
11
+ response = get_request(Target, 'getStats', params)
12
+ if response.success?
13
+ # strip out the 'Stat' keys which is just extra clutter
14
+ data = response.data.map do |stat|
15
+ stat["Stat"]
16
+ end
17
+ response.set_data data
18
+ end
19
+ response
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,88 @@
1
+ module HasOffers
2
+
3
+ class Response
4
+
5
+ attr_reader :test, :body, :http_status_code, :http_message, :http_headers
6
+
7
+ def success?
8
+ @http_status_code.to_s == '200' and status == 1
9
+ end
10
+
11
+ def test?
12
+ @test
13
+ end
14
+
15
+ def status
16
+ @body['response']['status']
17
+ end
18
+
19
+ # allows specific api calls to post-process the data for ease of use
20
+ def set_data(data)
21
+ @processed_data = data
22
+ end
23
+
24
+ def raw_data
25
+ @body
26
+ end
27
+
28
+ def data
29
+ @processed_data || (paginated_response? ? @body['response']['data']['data'] : @body['response']['data'])
30
+ end
31
+
32
+ def totals
33
+ # this is ready to go for Report.GetStats... not sure if totals is used elsewhere in which case the 'Stat'
34
+ # check here may not be generic enough
35
+ if @body['response']['data'] and @body['response']['data']['totals'] and @body['response']['data']['totals'].is_a?(Hash)
36
+ @body['response']['data']['totals']['Stat']
37
+ else
38
+ {}
39
+ end
40
+ end
41
+
42
+ def page_info
43
+ if paginated_response?
44
+ {'page_count' => @body['response']['data']['pageCount'],
45
+ 'current' => @body['response']['data']['current'],
46
+ 'count' => @body['response']['data']['count'],
47
+ 'page' => @body['response']['data']['page']}
48
+ else
49
+ {}
50
+ end
51
+ end
52
+
53
+ def validation_error?
54
+ status == -1 and data['error_code'] == 1
55
+ end
56
+
57
+ def error_messages
58
+ if data.is_a? Hash and data["errors"] and data["errors"]["error"]
59
+ data["errors"]["error"].map { |error| error["err_msg"] }
60
+ elsif @body["response"]["errors"]
61
+ @body["response"]["errors"].map { |error| error["err_msg"] }
62
+ else
63
+ []
64
+ end
65
+ end
66
+
67
+ def initialize(response)
68
+ if response.is_a? DummyResponse
69
+ @test = true
70
+ @body = response.body
71
+ else
72
+ @test = false
73
+ @body = Yajl::Parser.parse(response.body)
74
+ end
75
+ @http_status_code = response.code
76
+ @http_message = response.message
77
+ @http_headers = response.to_hash
78
+ end
79
+
80
+ protected
81
+
82
+ def paginated_response?
83
+ @body['response']['data'] and @body['response']['data'].is_a?(Hash) and @body['response']['data']['pageCount']
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class AdvertiserTest < Test::Unit::TestCase
4
+
5
+ def test_find_all
6
+ response = HasOffers::Advertiser.find_all
7
+ assert_success response
8
+ end
9
+
10
+ def good_params
11
+ { 'company' => 'Dominoes',
12
+ 'address1' => '100 1st St.',
13
+ 'city' => 'Minneapolis',
14
+ 'country' => 'USA',
15
+ 'zipcode' => '55413',
16
+ 'phone' => '123-123-1234' }
17
+ end
18
+
19
+ def test_create
20
+ response = HasOffers::Advertiser.create(good_params)
21
+ assert_success response
22
+ end
23
+
24
+ def test_update
25
+ response = HasOffers::Advertiser.update(1, 'company' => "Dominoes Pizza")
26
+ assert_success response
27
+ end
28
+
29
+ end
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class AffiliateBillingTest < Test::Unit::TestCase
4
+
5
+ def test_find_invoice_stats
6
+ response = HasOffers::AffiliateBilling.find_invoice_stats('affiliate_id' => 1, 'start_date' => "06/23/10", 'end_date' => "07/23/10")
7
+ assert_success response
8
+ end
9
+
10
+ def test_find_all_invoices
11
+ response = HasOffers::AffiliateBilling.find_all_invoices({})
12
+ assert_success response
13
+ assert response.data.length > 0, "No invoices were returned."
14
+ end
15
+
16
+ def test_find_all_invoices_filtered_by_affiliate
17
+ response = HasOffers::AffiliateBilling.find_all_invoices(
18
+ 'filters' => ['AffiliateInvoice.affiliate_id' => '7'],
19
+ 'fields' => ['is_paid', 'impressions', 'clicks', 'conversions', 'amount']
20
+ )
21
+ assert_success response
22
+ assert response.data.length > 0, "No invoices were returned."
23
+ end
24
+
25
+ def good_params
26
+ {'affiliate_id' => '1',
27
+ 'start_date' => '2010-01-01',
28
+ 'end_date' => '2010-01-31',
29
+ 'status' => 'active'
30
+ }
31
+ end
32
+
33
+ def test_create
34
+ response = HasOffers::AffiliateBilling.create_invoice(good_params)
35
+ assert_success response
36
+ end
37
+
38
+ def test_update
39
+ response = HasOffers::AffiliateBilling.update_invoice(1, {'status' => 'deleted'})
40
+ assert_success response
41
+ end
42
+
43
+ end
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class AffiliateTest < Test::Unit::TestCase
4
+
5
+ def good_params
6
+ {'company' => 'Hockey Organization',
7
+ 'address1' => '100 East 1st St.',
8
+ 'city' => 'Minneapolis',
9
+ 'country' => 'USA',
10
+ 'zipcode' => '55431',
11
+ 'region' => 'MN',
12
+ 'phone' => '123-123-1234'
13
+ }
14
+ end
15
+
16
+ def test_create
17
+ response = HasOffers::Affiliate.create(good_params)
18
+ assert_success response
19
+ end
20
+
21
+ def test_update
22
+ response = HasOffers::Affiliate.update(1, {'company' => 'Hockey Organization',
23
+ 'address1' => '100 East 1st St.',
24
+ 'city' => 'Minneapolis',
25
+ 'country' => 'USA',
26
+ 'zipcode' => '55431',
27
+ 'region' => 'MN',
28
+ 'phone' => '123-123-1234'})
29
+ assert_success response
30
+ end
31
+
32
+ end
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ConversionTest < Test::Unit::TestCase
4
+
5
+ def good_params
6
+ {'affiliate_id' => '1', 'offer_id' => '1', 'payout' => '10.50', 'revenue' => '5.75'}
7
+ end
8
+
9
+ def test_create
10
+ response = HasOffers::Conversion.create(good_params)
11
+ assert_success response
12
+ end
13
+
14
+ def test_update
15
+ response = HasOffers::Conversion.update(1, {'affiliate_id' => '1', 'offer_id' => '1', 'payout' => '11.50', 'revenue' => '6.75'})
16
+ assert_success response
17
+ end
18
+
19
+ end
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class OfferTest < Test::Unit::TestCase
4
+
5
+ def good_params
6
+ {
7
+ 'name' => 'Test',
8
+ 'description' => 'Test',
9
+ 'advertiser_id' => '1',
10
+ 'offer_url' => 'test',
11
+ 'preview_url' => 'test',
12
+ 'protocol' => 'https',
13
+ 'status' => 'active',
14
+ 'expiration_date' => (Date.today + 30).to_s,
15
+ 'payout_type' => 'cpa_flat',
16
+ 'revenue_type' => 'cpa_both',
17
+ 'default_payout' => '4.50',
18
+ 'max_payout' => '2.50',
19
+ 'max_percent_payout' => '15.00'
20
+ }
21
+ end
22
+
23
+ def test_create
24
+ response = HasOffers::Offer.create(good_params)
25
+ assert_success response
26
+ end
27
+
28
+ def test_update
29
+ response = HasOffers::Offer.update(1, 'name' => "Test")
30
+ assert_success response
31
+ end
32
+
33
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ReportTest < Test::Unit::TestCase
4
+
5
+ def test_get_stats
6
+ response = HasOffers::Report.get_stats(
7
+ 'fields' => ['Stat.clicks'],
8
+ 'filters' => ['Stat.affiliate_id' => ['values' => 1, 'conditional' => 'EQUAL_TO']]
9
+ )
10
+ assert_success response
11
+ end
12
+
13
+ end
@@ -0,0 +1,7 @@
1
+ require "test/unit"
2
+ require "rubygems"
3
+ require "hasoffers"
4
+
5
+ def assert_success(response)
6
+ assert response.success?, "Failed with error messages: #{response.error_messages}"
7
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hasoffers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Luke Ludwig
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-07-13 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: yajl-ruby
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ - - "="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.7.6
27
+ version:
28
+ - !ruby/object:Gem::Dependency
29
+ name: crack
30
+ type: :runtime
31
+ version_requirement:
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: "0"
37
+ - - "="
38
+ - !ruby/object:Gem::Version
39
+ version: 0.1.6
40
+ version:
41
+ description: Implementation of the HasOffers API for affiliate advertising.
42
+ email: luke.ludwig@tstmedia.com
43
+ executables: []
44
+
45
+ extensions: []
46
+
47
+ extra_rdoc_files:
48
+ - CHANGELOG
49
+ - README.rdoc
50
+ - lib/has_offers_model.rb
51
+ - lib/hasoffers.rb
52
+ - lib/hasoffers/advertiser.rb
53
+ - lib/hasoffers/affiliate.rb
54
+ - lib/hasoffers/affiliate_billing.rb
55
+ - lib/hasoffers/base.rb
56
+ - lib/hasoffers/conversion.rb
57
+ - lib/hasoffers/dummy_response.rb
58
+ - lib/hasoffers/offer.rb
59
+ - lib/hasoffers/report.rb
60
+ - lib/hasoffers/response.rb
61
+ files:
62
+ - CHANGELOG
63
+ - README.rdoc
64
+ - Rakefile
65
+ - config/has_offers.yml
66
+ - lib/has_offers_model.rb
67
+ - lib/hasoffers.rb
68
+ - lib/hasoffers/advertiser.rb
69
+ - lib/hasoffers/affiliate.rb
70
+ - lib/hasoffers/affiliate_billing.rb
71
+ - lib/hasoffers/base.rb
72
+ - lib/hasoffers/conversion.rb
73
+ - lib/hasoffers/dummy_response.rb
74
+ - lib/hasoffers/offer.rb
75
+ - lib/hasoffers/report.rb
76
+ - lib/hasoffers/response.rb
77
+ - test/advertiser_test.rb
78
+ - test/affiliate_billing_test.rb
79
+ - test/affiliate_test.rb
80
+ - test/conversion_test.rb
81
+ - test/offer_test.rb
82
+ - test/report_test.rb
83
+ - test/test_helper.rb
84
+ - Manifest
85
+ - hasoffers.gemspec
86
+ has_rdoc: true
87
+ homepage: http://github.com/ngin/hasoffers
88
+ licenses: []
89
+
90
+ post_install_message:
91
+ rdoc_options:
92
+ - --line-numbers
93
+ - --inline-source
94
+ - --title
95
+ - Hasoffers
96
+ - --main
97
+ - README.rdoc
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: "0"
105
+ version:
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: "1.2"
111
+ version:
112
+ requirements: []
113
+
114
+ rubyforge_project: hasoffers
115
+ rubygems_version: 1.3.5
116
+ signing_key:
117
+ specification_version: 3
118
+ summary: Implementation of the HasOffers API for affiliate advertising.
119
+ test_files:
120
+ - test/advertiser_test.rb
121
+ - test/affiliate_billing_test.rb
122
+ - test/affiliate_test.rb
123
+ - test/conversion_test.rb
124
+ - test/offer_test.rb
125
+ - test/report_test.rb
126
+ - test/test_helper.rb