soapy_cake 0.2.12 → 0.3.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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/README.md +2 -2
- data/lib/soapy_cake.rb +3 -1
- data/lib/soapy_cake/admin.rb +87 -0
- data/lib/soapy_cake/advertiser.rb +21 -0
- data/lib/soapy_cake/affiliate.rb +29 -0
- data/lib/soapy_cake/client.rb +3 -153
- data/lib/soapy_cake/client/cake_client.rb +157 -0
- data/lib/soapy_cake/client/http_client.rb +14 -0
- data/lib/soapy_cake/version.rb +1 -1
- data/spec/lib/soapy_cake/admin_spec.rb +251 -0
- data/spec/lib/soapy_cake/advertiser_spec.rb +14 -0
- data/spec/lib/soapy_cake/affiliate_spec.rb +50 -0
- data/spec/lib/soapy_cake/{client_spec.rb → client/cake_client_spec.rb} +7 -7
- metadata +15 -5
- data/lib/soapy_cake/http_client.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ab8351326e52185986163c48544e4290cb8e907
|
4
|
+
data.tar.gz: a0804c9ff6715e168d22388ecf88682641dcf07d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 101062b3e3babb569f02a6e4c3c3c02d8e4430a1ac6ccbb7c8c47fadd74a50b7ae1dec77e8abdbe07386892ce9235647efccd7de9982ed4deec887cb5ba9e235
|
7
|
+
data.tar.gz: f49d9f6d551c28ab57ae4f09ae857cb1424646eb98d2ae940d3a182e5b329c849a6a04f88dcca3719eb3c14a77b0464db2353a30f4264c770c6a87c44c02991a
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1.
|
1
|
+
2.1.4
|
data/README.md
CHANGED
@@ -29,13 +29,13 @@ environment variables.
|
|
29
29
|
Export all advertisers:
|
30
30
|
|
31
31
|
```ruby
|
32
|
-
SoapyCake::Client.export.advertisers(opts)
|
32
|
+
SoapyCake::Client::CakeClient.export.advertisers(opts)
|
33
33
|
```
|
34
34
|
|
35
35
|
Get report for specific date range:
|
36
36
|
|
37
37
|
```ruby
|
38
|
-
SoapyCake::Client.reports.affiliate_summary(
|
38
|
+
SoapyCake::Client::CakeClient.reports.affiliate_summary(
|
39
39
|
start_date: Date.beginning_of_month,
|
40
40
|
end_date: Date.today
|
41
41
|
)
|
data/lib/soapy_cake.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'active_support/core_ext/string'
|
2
2
|
require 'active_support/core_ext/date'
|
3
3
|
require 'soapy_cake/version'
|
4
|
-
require 'soapy_cake/http_client'
|
5
4
|
require 'soapy_cake/client'
|
5
|
+
require 'soapy_cake/admin'
|
6
|
+
require 'soapy_cake/advertiser'
|
7
|
+
require 'soapy_cake/affiliate'
|
6
8
|
|
7
9
|
module SoapyCake
|
8
10
|
API_VERSIONS = YAML.load(File.read(File.expand_path('../../api_versions.yml', __FILE__)))
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module SoapyCake
|
2
|
+
class Admin
|
3
|
+
def initialize(_opts = {})
|
4
|
+
end
|
5
|
+
|
6
|
+
def affiliate_bills(opts = {})
|
7
|
+
Client::CakeClient.accounting.export_affiliate_bills(opts)
|
8
|
+
end
|
9
|
+
|
10
|
+
def advertiser_bills(opts = {})
|
11
|
+
Client::CakeClient.accounting.export_advertiser_bills(opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
def affiliate_bill_received!(opts = {})
|
15
|
+
Client::CakeClient.accounting.mark_affiliate_bill_as_received(opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def advertisers(opts = {})
|
19
|
+
Client::CakeClient.export.advertisers(opts)
|
20
|
+
end
|
21
|
+
|
22
|
+
def affiliates(opts = {})
|
23
|
+
Client::CakeClient.export.affiliates(opts)
|
24
|
+
end
|
25
|
+
|
26
|
+
def campaigns(opts = {})
|
27
|
+
Client::CakeClient.export.campaigns(opts)
|
28
|
+
end
|
29
|
+
|
30
|
+
def offers(opts = {})
|
31
|
+
Client::CakeClient.export.offers(opts)
|
32
|
+
end
|
33
|
+
|
34
|
+
def campaign_summary(opts)
|
35
|
+
Client::CakeClient.reports.campaign_summary(opts_with_date_range(opts))
|
36
|
+
end
|
37
|
+
|
38
|
+
def offer_summary(opts)
|
39
|
+
Client::CakeClient.reports.offer_summary(opts_with_date_range(opts))
|
40
|
+
end
|
41
|
+
|
42
|
+
def affiliate_summary(opts)
|
43
|
+
Client::CakeClient.reports.affiliate_summary(opts_with_date_range(opts))
|
44
|
+
end
|
45
|
+
|
46
|
+
def advertiser_summary(opts)
|
47
|
+
Client::CakeClient.reports.advertiser_summary(opts_with_date_range(opts))
|
48
|
+
end
|
49
|
+
|
50
|
+
def conversions(opts)
|
51
|
+
Client::CakeClient.reports.conversions(opts.merge(conversion_type: 'conversions'))
|
52
|
+
end
|
53
|
+
|
54
|
+
def events(opts)
|
55
|
+
Client::CakeClient.reports.conversions(opts.merge(conversion_type: 'events'))
|
56
|
+
end
|
57
|
+
|
58
|
+
def currencies
|
59
|
+
Client::CakeClient.get.currencies
|
60
|
+
end
|
61
|
+
|
62
|
+
def mark_affiliate_bill_as_paid(opts)
|
63
|
+
Client::CakeClient.accounting.mark_affiliate_bill_as_paid(opts)
|
64
|
+
end
|
65
|
+
|
66
|
+
def creatives(opts = {})
|
67
|
+
Client::CakeClient.export.creatives(opts)
|
68
|
+
end
|
69
|
+
|
70
|
+
def update_creative(opts = {})
|
71
|
+
Client::CakeClient.addedit.creative(opts)
|
72
|
+
end
|
73
|
+
|
74
|
+
def traffic(opts)
|
75
|
+
Client::CakeClient.reports.traffic_export(opts_with_date_range(opts))
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def opts_with_date_range(opts)
|
81
|
+
start_date = opts[:start_date].to_date
|
82
|
+
end_date = opts[:end_date] || start_date + 1
|
83
|
+
|
84
|
+
opts.merge(start_date: start_date, end_date: end_date)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SoapyCake
|
2
|
+
class Advertiser
|
3
|
+
attr_reader :api_key, :advertiser_id
|
4
|
+
|
5
|
+
def initialize(opts = {})
|
6
|
+
@api_key = opts[:api_key]
|
7
|
+
@advertiser_id = opts[:advertiser_id]
|
8
|
+
end
|
9
|
+
|
10
|
+
def bills(opts = {})
|
11
|
+
cake_client(:reports, :bills, opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def cake_client(api, method, opts = {})
|
17
|
+
Client::CakeClient.send(api, role: :advertisers)
|
18
|
+
.public_send(method, opts.merge(advertiser_id: advertiser_id, api_key: api_key))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SoapyCake
|
2
|
+
class Affiliate
|
3
|
+
attr_reader :api_key, :affiliate_id
|
4
|
+
|
5
|
+
def initialize(opts = {})
|
6
|
+
@api_key = opts[:api_key]
|
7
|
+
@affiliate_id = opts[:affiliate_id]
|
8
|
+
end
|
9
|
+
|
10
|
+
def bills(opts = {})
|
11
|
+
cake_client(:reports, :bills, opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
def offer_feed(opts = {})
|
15
|
+
cake_client(:offers, :offer_feed, opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def campaign(opts = {})
|
19
|
+
cake_client(:offers, :get_campaign, opts)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def cake_client(api, method, opts = {})
|
25
|
+
Client::CakeClient.send(api, role: :affiliates)
|
26
|
+
.send(method, opts.merge(affiliate_id: affiliate_id, api_key: api_key))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/soapy_cake/client.rb
CHANGED
@@ -1,155 +1,5 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require 'local_copy'
|
1
|
+
require 'soapy_cake/client/http_client'
|
2
|
+
require 'soapy_cake/client/cake_client'
|
4
3
|
|
5
|
-
module SoapyCake
|
6
|
-
class Client
|
7
|
-
attr_reader :service, :api_key, :domain, :role
|
8
|
-
|
9
|
-
def initialize(service, opts = {})
|
10
|
-
@service = service.to_sym
|
11
|
-
@version = opts[:version]
|
12
|
-
@role = opts[:role] || :admin
|
13
|
-
|
14
|
-
@domain = opts.fetch(:domain) do
|
15
|
-
if ENV['CAKE_DOMAIN'].present?
|
16
|
-
ENV['CAKE_DOMAIN']
|
17
|
-
else
|
18
|
-
fail 'We need a domain'
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
@api_key = opts.fetch(:api_key) do
|
23
|
-
if opts[:username] && opts[:password]
|
24
|
-
get_api_key(opts[:username], opts[:password])
|
25
|
-
elsif ENV['CAKE_API_KEY']
|
26
|
-
ENV['CAKE_API_KEY']
|
27
|
-
else
|
28
|
-
fail 'We need an API key here!'
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.method_missing(method, opts = {})
|
34
|
-
new(method, opts)
|
35
|
-
end
|
36
|
-
|
37
|
-
def sekken_client(method)
|
38
|
-
self.class.sekken_client(wsdl_url(version(method)))
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.sekken_client(url)
|
42
|
-
path = LocalCopy.fetch(url)
|
43
|
-
@sekken_clients ||= {}
|
44
|
-
@sekken_clients[url] ||= Sekken.new(path, HTTPartySekken.new)
|
45
|
-
end
|
46
|
-
|
47
|
-
def method_missing(method, opts = {})
|
48
|
-
if supported?(method)
|
49
|
-
method = method.to_s
|
50
|
-
operation = sekken_client(method).operation(service, "#{service}Soap12", method.camelize)
|
51
|
-
operation.body = build_body(method, opts)
|
52
|
-
process_response(method, operation.call.body)
|
53
|
-
else
|
54
|
-
super
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def known_params_for(method)
|
59
|
-
method = method.to_s
|
60
|
-
operation = sekken_client(method).operation(service, "#{service}Soap12", method.camelize)
|
61
|
-
operation.example_body
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def build_body(method, opts)
|
67
|
-
{
|
68
|
-
method.camelize.to_sym => { api_key: api_key }.merge(
|
69
|
-
opts.each_with_object({}) do |(key, value), memo|
|
70
|
-
memo[key] = format_param(value)
|
71
|
-
end
|
72
|
-
)
|
73
|
-
}
|
74
|
-
end
|
75
|
-
|
76
|
-
def format_param(value)
|
77
|
-
case value
|
78
|
-
when Time
|
79
|
-
value.utc.strftime('%Y-%m-%dT%H:%M:%S')
|
80
|
-
when Date
|
81
|
-
value.strftime('%Y-%m-%dT00:00:00')
|
82
|
-
else
|
83
|
-
value
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def process_response(method, response)
|
88
|
-
Time.use_zone('UTC') do
|
89
|
-
fail RequestUnsuccessful, response[:fault][:reason][:text] if response[:fault]
|
90
|
-
node_name = {
|
91
|
-
'affiliate_summary' => 'affiliates',
|
92
|
-
'advertiser_summary' => 'advertisers',
|
93
|
-
'affiliate_tags' => 'tags',
|
94
|
-
'offer_summary' => 'offers',
|
95
|
-
'campaign_summary' => 'campaigns',
|
96
|
-
'offer_feed' => 'offers',
|
97
|
-
'export_affiliate_bills' => 'affiliate_bills',
|
98
|
-
'export_advertiser_bills' => 'advertiser_bills',
|
99
|
-
}.fetch(method, method)
|
100
|
-
|
101
|
-
result = response[:"#{method}_response"][:"#{method}_result"]
|
102
|
-
fail RequestUnsuccessful, result[:message] if result[:success] == false
|
103
|
-
return result unless result_has_collection?(result, method)
|
104
|
-
extract_collection(node_name, result)
|
105
|
-
.map { |hash| remove_prefix(node_name, hash) }
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def result_has_collection?(result, method)
|
110
|
-
!result.key?(:message) && !method.to_s.starts_with?('get_')
|
111
|
-
end
|
112
|
-
|
113
|
-
def extract_collection(node_name, response)
|
114
|
-
node_name = node_name.to_sym
|
115
|
-
if response.key?(node_name)
|
116
|
-
return [] if response[node_name].nil?
|
117
|
-
response = response[node_name]
|
118
|
-
end
|
119
|
-
[response[response.keys.first]].flatten
|
120
|
-
end
|
121
|
-
|
122
|
-
def remove_prefix(prefix, object)
|
123
|
-
object.each_with_object({}) do |(k, v), m|
|
124
|
-
prefix_ = "#{prefix.singularize}_"
|
125
|
-
if k.to_s.start_with?(prefix_)
|
126
|
-
m[k[(prefix_.size)..-1].to_sym] = v
|
127
|
-
else
|
128
|
-
m[k] = v
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def get_api_key(username, password)
|
134
|
-
operation = sekken_client(:get_api_key).operation('get', 'getSoap12', 'GetAPIKey')
|
135
|
-
operation.body = { GetAPIKey: { username: username, password: password } }
|
136
|
-
response = operation.call.body
|
137
|
-
response[:get_api_key_response][:get_api_key_result]
|
138
|
-
end
|
139
|
-
|
140
|
-
def wsdl_url(version)
|
141
|
-
role_path = (role && role != :admin) ? "/#{role}" : nil
|
142
|
-
"https://#{domain}#{role_path}/api/#{version}/#{service}.asmx?WSDL"
|
143
|
-
end
|
144
|
-
|
145
|
-
def version(method)
|
146
|
-
API_VERSIONS[role][service][method.to_sym]
|
147
|
-
end
|
148
|
-
|
149
|
-
def supported?(method)
|
150
|
-
API_VERSIONS[role][service].keys.include?(method)
|
151
|
-
end
|
152
|
-
|
153
|
-
class RequestUnsuccessful < RuntimeError; end
|
154
|
-
end
|
4
|
+
module SoapyCake::Client
|
155
5
|
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'sekken'
|
2
|
+
require 'active_support/core_ext/time/zones'
|
3
|
+
require 'local_copy'
|
4
|
+
|
5
|
+
module SoapyCake
|
6
|
+
module Client
|
7
|
+
class CakeClient
|
8
|
+
attr_reader :service, :api_key, :domain, :role
|
9
|
+
|
10
|
+
def initialize(service, opts = {})
|
11
|
+
@service = service.to_sym
|
12
|
+
@version = opts[:version]
|
13
|
+
@role = opts[:role] || :admin
|
14
|
+
|
15
|
+
@domain = opts.fetch(:domain) do
|
16
|
+
if ENV['CAKE_DOMAIN'].present?
|
17
|
+
ENV['CAKE_DOMAIN']
|
18
|
+
else
|
19
|
+
fail 'We need a domain'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
@api_key = opts.fetch(:api_key) do
|
24
|
+
if opts[:username] && opts[:password]
|
25
|
+
get_api_key(opts[:username], opts[:password])
|
26
|
+
elsif ENV['CAKE_API_KEY']
|
27
|
+
ENV['CAKE_API_KEY']
|
28
|
+
else
|
29
|
+
fail 'We need an API key here!'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.method_missing(method, opts = {})
|
35
|
+
new(method, opts)
|
36
|
+
end
|
37
|
+
|
38
|
+
def sekken_client(method)
|
39
|
+
self.class.sekken_client(wsdl_url(version(method)))
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.sekken_client(url)
|
43
|
+
path = LocalCopy.fetch(url)
|
44
|
+
@sekken_clients ||= {}
|
45
|
+
@sekken_clients[url] ||= Sekken.new(path, HTTPartySekken.new)
|
46
|
+
end
|
47
|
+
|
48
|
+
def method_missing(method, opts = {})
|
49
|
+
if supported?(method)
|
50
|
+
method = method.to_s
|
51
|
+
operation = sekken_client(method).operation(service, "#{service}Soap12", method.camelize)
|
52
|
+
operation.body = build_body(method, opts)
|
53
|
+
process_response(method, operation.call.body)
|
54
|
+
else
|
55
|
+
super
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def known_params_for(method)
|
60
|
+
method = method.to_s
|
61
|
+
operation = sekken_client(method).operation(service, "#{service}Soap12", method.camelize)
|
62
|
+
operation.example_body
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def build_body(method, opts)
|
68
|
+
{
|
69
|
+
method.camelize.to_sym => { api_key: api_key }.merge(
|
70
|
+
opts.each_with_object({}) do |(key, value), memo|
|
71
|
+
memo[key] = format_param(value)
|
72
|
+
end
|
73
|
+
)
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def format_param(value)
|
78
|
+
case value
|
79
|
+
when Time
|
80
|
+
value.utc.strftime('%Y-%m-%dT%H:%M:%S')
|
81
|
+
when Date
|
82
|
+
value.strftime('%Y-%m-%dT00:00:00')
|
83
|
+
else
|
84
|
+
value
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_response(method, response)
|
89
|
+
Time.use_zone('UTC') do
|
90
|
+
fail RequestUnsuccessful, response[:fault][:reason][:text] if response[:fault]
|
91
|
+
node_name = {
|
92
|
+
'affiliate_summary' => 'affiliates',
|
93
|
+
'advertiser_summary' => 'advertisers',
|
94
|
+
'affiliate_tags' => 'tags',
|
95
|
+
'offer_summary' => 'offers',
|
96
|
+
'campaign_summary' => 'campaigns',
|
97
|
+
'offer_feed' => 'offers',
|
98
|
+
'export_affiliate_bills' => 'affiliate_bills',
|
99
|
+
'export_advertiser_bills' => 'advertiser_bills',
|
100
|
+
}.fetch(method, method)
|
101
|
+
|
102
|
+
result = response[:"#{method}_response"][:"#{method}_result"]
|
103
|
+
fail RequestUnsuccessful, result[:message] if result[:success] == false
|
104
|
+
return result unless result_has_collection?(result, method)
|
105
|
+
extract_collection(node_name, result)
|
106
|
+
.map { |hash| remove_prefix(node_name, hash) }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def result_has_collection?(result, method)
|
111
|
+
!result.key?(:message) && !method.to_s.starts_with?('get_')
|
112
|
+
end
|
113
|
+
|
114
|
+
def extract_collection(node_name, response)
|
115
|
+
node_name = node_name.to_sym
|
116
|
+
if response.key?(node_name)
|
117
|
+
return [] if response[node_name].nil?
|
118
|
+
response = response[node_name]
|
119
|
+
end
|
120
|
+
[response[response.keys.first]].flatten
|
121
|
+
end
|
122
|
+
|
123
|
+
def remove_prefix(prefix, object)
|
124
|
+
object.each_with_object({}) do |(k, v), m|
|
125
|
+
prefix_ = "#{prefix.singularize}_"
|
126
|
+
if k.to_s.start_with?(prefix_)
|
127
|
+
m[k[(prefix_.size)..-1].to_sym] = v
|
128
|
+
else
|
129
|
+
m[k] = v
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def get_api_key(username, password)
|
135
|
+
operation = sekken_client(:get_api_key).operation('get', 'getSoap12', 'GetAPIKey')
|
136
|
+
operation.body = { GetAPIKey: { username: username, password: password } }
|
137
|
+
response = operation.call.body
|
138
|
+
response[:get_api_key_response][:get_api_key_result]
|
139
|
+
end
|
140
|
+
|
141
|
+
def wsdl_url(version)
|
142
|
+
role_path = (role && role != :admin) ? "/#{role}" : nil
|
143
|
+
"https://#{domain}#{role_path}/api/#{version}/#{service}.asmx?WSDL"
|
144
|
+
end
|
145
|
+
|
146
|
+
def version(method)
|
147
|
+
API_VERSIONS[role][service][method.to_sym]
|
148
|
+
end
|
149
|
+
|
150
|
+
def supported?(method)
|
151
|
+
API_VERSIONS[role][service].keys.include?(method)
|
152
|
+
end
|
153
|
+
|
154
|
+
class RequestUnsuccessful < RuntimeError; end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
data/lib/soapy_cake/version.rb
CHANGED
@@ -0,0 +1,251 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SoapyCake::Admin do
|
4
|
+
describe '.affiliate_bill_received!' do
|
5
|
+
it 'marks an affiliate bill as received' do
|
6
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
7
|
+
.to receive(:mark_affiliate_bill_as_received)
|
8
|
+
.with(affiliate_id: 2)
|
9
|
+
|
10
|
+
subject.affiliate_bill_received!(affiliate_id: 2)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '.affiliate_bills' do
|
15
|
+
it 'exports bills' do
|
16
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
17
|
+
.to receive(:export_affiliate_bills)
|
18
|
+
.with(affiliate_id: 2)
|
19
|
+
|
20
|
+
subject.affiliate_bills(affiliate_id: 2)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '.advertiser_bills' do
|
25
|
+
it 'exports bills' do
|
26
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
27
|
+
.to receive(:export_advertiser_bills)
|
28
|
+
.with(advertiser_id: 2)
|
29
|
+
|
30
|
+
subject.advertiser_bills(advertiser_id: 2)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.campaign_summary' do
|
35
|
+
let(:start_date) { Date.new(2014, 7, 1) }
|
36
|
+
let(:end_date) { Date.new(2014, 7, 3) }
|
37
|
+
|
38
|
+
it 'returns the campaign summary report for the given days' do
|
39
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
40
|
+
.to receive(:campaign_summary)
|
41
|
+
.with(start_date: start_date, end_date: end_date, offer_id: 12)
|
42
|
+
.and_return('result')
|
43
|
+
|
44
|
+
expect(subject.campaign_summary(start_date: start_date, end_date: end_date, offer_id: 12))
|
45
|
+
.to eq('result')
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns the campaign summary report for the start_date if no end_date is given' do
|
49
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
50
|
+
.to receive(:campaign_summary)
|
51
|
+
.with(start_date: start_date, end_date: start_date + 1, offer_id: 12)
|
52
|
+
.and_return('result')
|
53
|
+
|
54
|
+
expect(subject.campaign_summary(start_date: start_date, offer_id: 12))
|
55
|
+
.to eq('result')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
describe '.advertisers' do
|
61
|
+
it 'returns advertisers' do
|
62
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
63
|
+
.to receive(:advertisers)
|
64
|
+
|
65
|
+
subject.advertisers
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '.affiliates' do
|
70
|
+
it 'returns affiliates' do
|
71
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
72
|
+
.to receive(:affiliates)
|
73
|
+
|
74
|
+
subject.affiliates(force: true)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '.campaigns' do
|
79
|
+
it 'returns all campaigns' do
|
80
|
+
opts = { foo: :bar }
|
81
|
+
expected = [{ ping: :pong }]
|
82
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
83
|
+
.to receive(:campaigns)
|
84
|
+
.with(opts).and_return(expected)
|
85
|
+
expect(subject.campaigns(opts)).to eq(expected)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '.offers' do
|
90
|
+
it 'returns all offers' do
|
91
|
+
opts = { foo: :bar }
|
92
|
+
expected = [{ ping: :pong }]
|
93
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
94
|
+
.to receive(:offers)
|
95
|
+
.with(opts).and_return(expected)
|
96
|
+
expect(subject.offers(opts)).to eq(expected)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '.affiliate_summary' do
|
101
|
+
let(:start_date) { Date.new(2014, 7, 1) }
|
102
|
+
let(:end_date) { Date.new(2014, 7, 3) }
|
103
|
+
|
104
|
+
it 'returns the affiliate summary report for the given days' do
|
105
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
106
|
+
.to receive(:affiliate_summary)
|
107
|
+
.with(start_date: start_date, end_date: end_date).and_return(
|
108
|
+
[{ affiliate: { affiliate_id: '1' } },
|
109
|
+
{ affiliate: { affiliate_id: '2' } }]
|
110
|
+
)
|
111
|
+
|
112
|
+
expect(subject.affiliate_summary(start_date: start_date, end_date: end_date))
|
113
|
+
.to eq(
|
114
|
+
[{ affiliate: { affiliate_id: '1' } },
|
115
|
+
{ affiliate: { affiliate_id: '2' } }]
|
116
|
+
)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'returns the affiliate summary report for the start_date if no end_date is given' do
|
120
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
121
|
+
.to receive(:affiliate_summary)
|
122
|
+
.with(start_date: start_date, end_date: start_date + 1).and_return(
|
123
|
+
[{ affiliate: { affiliate_id: '1' } },
|
124
|
+
{ affiliate: { affiliate_id: '2' } }]
|
125
|
+
)
|
126
|
+
|
127
|
+
expect(subject.affiliate_summary(start_date: start_date)).to eq(
|
128
|
+
[{ affiliate: { affiliate_id: '1' } },
|
129
|
+
{ affiliate: { affiliate_id: '2' } }]
|
130
|
+
)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe '.advertiser_summary' do
|
135
|
+
let(:start_date) { Date.new(2014, 7, 1) }
|
136
|
+
let(:end_date) { Date.new(2014, 7, 3) }
|
137
|
+
|
138
|
+
it 'returns the advertiser summary report for the given days' do
|
139
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
140
|
+
.to receive(:advertiser_summary)
|
141
|
+
.with(start_date: start_date, end_date: end_date).and_return(
|
142
|
+
[{ advertiser: { advertiser_id: '1' } },
|
143
|
+
{ advertiser: { advertiser_id: '2' } }]
|
144
|
+
)
|
145
|
+
|
146
|
+
expect(subject.advertiser_summary(start_date: start_date, end_date: end_date))
|
147
|
+
.to eq(
|
148
|
+
[{ advertiser: { advertiser_id: '1' } },
|
149
|
+
{ advertiser: { advertiser_id: '2' } }]
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'returns the advertiser summary report for the start_date if no end_date is given' do
|
154
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
155
|
+
.to receive(:advertiser_summary)
|
156
|
+
.with(start_date: start_date, end_date: start_date + 1).and_return(
|
157
|
+
[{ advertiser: { advertiser_id: '1' } },
|
158
|
+
{ advertiser: { advertiser_id: '2' } }]
|
159
|
+
)
|
160
|
+
|
161
|
+
expect(subject.advertiser_summary(start_date: start_date)).to eq(
|
162
|
+
[{ advertiser: { advertiser_id: '1' } },
|
163
|
+
{ advertiser: { advertiser_id: '2' } }]
|
164
|
+
)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '.offer_summary' do
|
169
|
+
let(:start_date) { Date.new(2014, 7, 1) }
|
170
|
+
let(:end_date) { Date.new(2014, 7, 3) }
|
171
|
+
|
172
|
+
it 'returns the offer summary report for the given days' do
|
173
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
174
|
+
.to receive(:offer_summary)
|
175
|
+
.with(start_date: start_date, end_date: end_date, offer_id: 1)
|
176
|
+
.and_return('result')
|
177
|
+
|
178
|
+
expect(subject.offer_summary(start_date: start_date, end_date: end_date, offer_id: 1))
|
179
|
+
.to eq('result')
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'returns the offer summary report for the start_date if no end_date is given' do
|
183
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
184
|
+
.to receive(:offer_summary)
|
185
|
+
.with(start_date: start_date, end_date: start_date + 1, offer_id: 1)
|
186
|
+
.and_return('result')
|
187
|
+
|
188
|
+
expect(subject.offer_summary(start_date: start_date, offer_id: 1))
|
189
|
+
.to eq('result')
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '.conversions' do
|
194
|
+
it 'returns only conversions' do
|
195
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
196
|
+
.to receive(:conversions)
|
197
|
+
.with(color: 'green', conversion_type: 'conversions')
|
198
|
+
|
199
|
+
subject.conversions(color: 'green')
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe '.events' do
|
204
|
+
it 'returns only events' do
|
205
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
206
|
+
.to receive(:conversions)
|
207
|
+
.with(color: 'red', conversion_type: 'events')
|
208
|
+
|
209
|
+
subject.events(color: 'red')
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe '#mark_affiliate_bill_as_paid' do
|
214
|
+
it 'marks credit notes as paid' do
|
215
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
216
|
+
.to receive(:mark_affiliate_bill_as_paid).with(bill_id: 1)
|
217
|
+
subject.mark_affiliate_bill_as_paid(bill_id: 1)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe '#creatives' do
|
222
|
+
it 'fetches creatives from CAKE' do
|
223
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
224
|
+
.to receive(:creatives)
|
225
|
+
.with(offer_id: 1)
|
226
|
+
subject.creatives(offer_id: 1)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe '#traffic' do
|
231
|
+
let(:start_date) { Date.new(2014, 7, 1) }
|
232
|
+
let(:end_date) { Date.new(2014, 7, 3) }
|
233
|
+
|
234
|
+
it 'fetches a traffic report' do
|
235
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient)
|
236
|
+
.to receive(:traffic_export)
|
237
|
+
.with(start_date: start_date, end_date: end_date)
|
238
|
+
|
239
|
+
subject.traffic(start_date: start_date, end_date: end_date)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe '#update_creative' do
|
244
|
+
it 'updates a creative' do
|
245
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient).to receive(:creative)
|
246
|
+
.with(offer_id: 1, creative_status_id: 1)
|
247
|
+
|
248
|
+
subject.update_creative(offer_id: 1, creative_status_id: 1)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SoapyCake::Advertiser do
|
4
|
+
subject { described_class.new(api_key: 'abc', advertiser_id: 1) }
|
5
|
+
|
6
|
+
describe '.bills' do
|
7
|
+
it 'returns bills for an advertiser' do
|
8
|
+
expect_any_instance_of(SoapyCake::Client::CakeClient).to receive(:bills)
|
9
|
+
.with(advertiser_id: 1, api_key: 'abc')
|
10
|
+
|
11
|
+
subject.bills
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SoapyCake::Affiliate do
|
4
|
+
subject { described_class.new(api_key: 'abc', affiliate_id: 1) }
|
5
|
+
|
6
|
+
let(:client) { double('soap client') }
|
7
|
+
|
8
|
+
describe '#bills' do
|
9
|
+
it 'returns bills' do
|
10
|
+
expect(SoapyCake::Client::CakeClient).to receive(:reports)
|
11
|
+
.with(role: :affiliates)
|
12
|
+
.and_return(client)
|
13
|
+
|
14
|
+
expect(client).to receive(:bills).with(affiliate_id: 1, api_key: 'abc')
|
15
|
+
|
16
|
+
subject.bills
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#offer_feed' do
|
21
|
+
let(:offers) { double('offers') }
|
22
|
+
|
23
|
+
it 'returns offers' do
|
24
|
+
expect(SoapyCake::Client::CakeClient).to receive(:offers)
|
25
|
+
.with(role: :affiliates)
|
26
|
+
.and_return(client)
|
27
|
+
|
28
|
+
expect(client).to receive(:offer_feed)
|
29
|
+
.with(affiliate_id: 1, api_key: 'abc', status_id: 3)
|
30
|
+
.and_return(offers)
|
31
|
+
|
32
|
+
expect(subject.offer_feed(status_id: 3)).to eq(offers)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#campaign' do
|
37
|
+
let(:campaign) { double('campaign') }
|
38
|
+
|
39
|
+
it 'returns a campaign' do
|
40
|
+
expect(SoapyCake::Client::CakeClient).to receive(:offers)
|
41
|
+
.with(role: :affiliates)
|
42
|
+
.and_return(client)
|
43
|
+
|
44
|
+
expect(client).to receive(:get_campaign)
|
45
|
+
.with(affiliate_id: 1, api_key: 'abc', campaign_id: 12)
|
46
|
+
.and_return(campaign)
|
47
|
+
expect(subject.campaign(campaign_id: 12)).to eq(campaign)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
RSpec.describe SoapyCake::Client do
|
5
|
+
RSpec.describe SoapyCake::Client::CakeClient do
|
6
6
|
before do
|
7
|
-
|
7
|
+
described_class.instance_variable_set(:@sekken_clients, nil)
|
8
8
|
end
|
9
9
|
|
10
|
-
subject(:client) {
|
10
|
+
subject(:client) { described_class.new(:get, opts) }
|
11
11
|
let(:opts) { {} }
|
12
12
|
|
13
13
|
describe '.new' do
|
@@ -89,7 +89,7 @@ RSpec.describe SoapyCake::Client do
|
|
89
89
|
|
90
90
|
context 'for offer summary' do
|
91
91
|
subject do
|
92
|
-
|
92
|
+
described_class.new(:reports, opts).offer_summary(
|
93
93
|
start_date: Time.utc(2013, 1, 1),
|
94
94
|
end_date: Time.utc(2013, 1, 2)
|
95
95
|
)
|
@@ -177,20 +177,20 @@ RSpec.describe SoapyCake::Client do
|
|
177
177
|
client.send(:process_response, :affiliate, affiliate_response: {
|
178
178
|
affiliate_result: { message: 'FAIL!', success: false }
|
179
179
|
})
|
180
|
-
end.to raise_error(
|
180
|
+
end.to raise_error(described_class::RequestUnsuccessful, 'FAIL!')
|
181
181
|
end
|
182
182
|
|
183
183
|
it 'raises RequestUnsuccessful if response contains `:fault` key' do
|
184
184
|
expect do
|
185
185
|
client.send(:process_response, :affiliate,
|
186
186
|
fault: { reason: { text: 'FAIL!' } })
|
187
|
-
end.to raise_error(
|
187
|
+
end.to raise_error(described_class::RequestUnsuccessful, 'FAIL!')
|
188
188
|
end
|
189
189
|
end
|
190
190
|
|
191
191
|
describe 'instantiating through class method' do
|
192
192
|
it 'creates an instance with the service set according to the method name used' do
|
193
|
-
instance =
|
193
|
+
instance = described_class.get
|
194
194
|
expect(instance.service).to eq(:get)
|
195
195
|
end
|
196
196
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: soapy_cake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ad2games GmbH
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -166,8 +166,12 @@ files:
|
|
166
166
|
- Rakefile
|
167
167
|
- api_versions.yml
|
168
168
|
- lib/soapy_cake.rb
|
169
|
+
- lib/soapy_cake/admin.rb
|
170
|
+
- lib/soapy_cake/advertiser.rb
|
171
|
+
- lib/soapy_cake/affiliate.rb
|
169
172
|
- lib/soapy_cake/client.rb
|
170
|
-
- lib/soapy_cake/
|
173
|
+
- lib/soapy_cake/client/cake_client.rb
|
174
|
+
- lib/soapy_cake/client/http_client.rb
|
171
175
|
- lib/soapy_cake/version.rb
|
172
176
|
- script/update_versions.rb
|
173
177
|
- soapy_cake.gemspec
|
@@ -193,7 +197,10 @@ files:
|
|
193
197
|
- spec/fixtures/vcr_cassettes/client_new_verticals.yml
|
194
198
|
- spec/fixtures/vcr_cassettes/client_new_with_username_and_password.yml
|
195
199
|
- spec/fixtures/vcr_cassettes/client_sekken_client_caches_results.yml
|
196
|
-
- spec/lib/soapy_cake/
|
200
|
+
- spec/lib/soapy_cake/admin_spec.rb
|
201
|
+
- spec/lib/soapy_cake/advertiser_spec.rb
|
202
|
+
- spec/lib/soapy_cake/affiliate_spec.rb
|
203
|
+
- spec/lib/soapy_cake/client/cake_client_spec.rb
|
197
204
|
- spec/spec_helper.rb
|
198
205
|
homepage: http://ad2games.com
|
199
206
|
licenses:
|
@@ -242,5 +249,8 @@ test_files:
|
|
242
249
|
- spec/fixtures/vcr_cassettes/client_new_verticals.yml
|
243
250
|
- spec/fixtures/vcr_cassettes/client_new_with_username_and_password.yml
|
244
251
|
- spec/fixtures/vcr_cassettes/client_sekken_client_caches_results.yml
|
245
|
-
- spec/lib/soapy_cake/
|
252
|
+
- spec/lib/soapy_cake/admin_spec.rb
|
253
|
+
- spec/lib/soapy_cake/advertiser_spec.rb
|
254
|
+
- spec/lib/soapy_cake/affiliate_spec.rb
|
255
|
+
- spec/lib/soapy_cake/client/cake_client_spec.rb
|
246
256
|
- spec/spec_helper.rb
|