adtekio_adnetworks 0.0.4
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 +7 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +24 -0
- data/README.md +333 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/adtekio_adnetworks.gemspec +297 -0
- data/lib/adtekio_adnetworks.rb +6 -0
- data/lib/adtekio_adnetworks/api_key_scrapers.rb +59 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/adcolony.rb +20 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/applift.rb +13 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/applovin.rb +13 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/chartboost.rb +18 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/crossinstall.rb +13 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/leadbolt.rb +18 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/loopme.rb +12 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/mdotm.rb +22 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/revmob.rb +22 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/tapjoy.rb +19 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/unilead.rb +13 -0
- data/lib/adtekio_adnetworks/api_key_scrapers/vungle.rb +23 -0
- data/lib/adtekio_adnetworks/importers.rb +58 -0
- data/lib/adtekio_adnetworks/importers/cost/adcolony.rb +43 -0
- data/lib/adtekio_adnetworks/importers/cost/adquant.rb +68 -0
- data/lib/adtekio_adnetworks/importers/cost/appia.rb +47 -0
- data/lib/adtekio_adnetworks/importers/cost/applifier.rb +64 -0
- data/lib/adtekio_adnetworks/importers/cost/applift.rb +41 -0
- data/lib/adtekio_adnetworks/importers/cost/applovin.rb +52 -0
- data/lib/adtekio_adnetworks/importers/cost/bidmotion.rb +82 -0
- data/lib/adtekio_adnetworks/importers/cost/chartboost.rb +40 -0
- data/lib/adtekio_adnetworks/importers/cost/crossinstall.rb +34 -0
- data/lib/adtekio_adnetworks/importers/cost/facebook.rb +39 -0
- data/lib/adtekio_adnetworks/importers/cost/fractionalmedia.rb +104 -0
- data/lib/adtekio_adnetworks/importers/cost/fyber.rb +54 -0
- data/lib/adtekio_adnetworks/importers/cost/gamegenetics.rb +44 -0
- data/lib/adtekio_adnetworks/importers/cost/glispa.rb +59 -0
- data/lib/adtekio_adnetworks/importers/cost/googleadwords.rb +99 -0
- data/lib/adtekio_adnetworks/importers/cost/jampp.rb +57 -0
- data/lib/adtekio_adnetworks/importers/cost/leadbolt.rb +43 -0
- data/lib/adtekio_adnetworks/importers/cost/lifestreet.rb +49 -0
- data/lib/adtekio_adnetworks/importers/cost/loopme.rb +63 -0
- data/lib/adtekio_adnetworks/importers/cost/matomy.rb +65 -0
- data/lib/adtekio_adnetworks/importers/cost/mdotm.rb +69 -0
- data/lib/adtekio_adnetworks/importers/cost/mmg.rb +67 -0
- data/lib/adtekio_adnetworks/importers/cost/mnectar.rb +45 -0
- data/lib/adtekio_adnetworks/importers/cost/moboqo.rb +33 -0
- data/lib/adtekio_adnetworks/importers/cost/mobpartner.rb +46 -0
- data/lib/adtekio_adnetworks/importers/cost/nanigans.rb +114 -0
- data/lib/adtekio_adnetworks/importers/cost/revmob.rb +44 -0
- data/lib/adtekio_adnetworks/importers/cost/rtbmob.rb +48 -0
- data/lib/adtekio_adnetworks/importers/cost/startapp.rb +47 -0
- data/lib/adtekio_adnetworks/importers/cost/supersonic.rb +77 -0
- data/lib/adtekio_adnetworks/importers/cost/tapjoy.rb +42 -0
- data/lib/adtekio_adnetworks/importers/cost/tokenads.rb +46 -0
- data/lib/adtekio_adnetworks/importers/cost/unilead.rb +39 -0
- data/lib/adtekio_adnetworks/importers/cost/vungle.rb +58 -0
- data/lib/adtekio_adnetworks/importers/cost_import.rb +13 -0
- data/lib/adtekio_adnetworks/importers/revenue/adcolony.rb +67 -0
- data/lib/adtekio_adnetworks/importers/revenue/applifier.rb +55 -0
- data/lib/adtekio_adnetworks/importers/revenue/applovin.rb +58 -0
- data/lib/adtekio_adnetworks/importers/revenue/chartboost.rb +43 -0
- data/lib/adtekio_adnetworks/importers/revenue/flurry.rb +85 -0
- data/lib/adtekio_adnetworks/importers/revenue/fyber.rb +61 -0
- data/lib/adtekio_adnetworks/importers/revenue/hypr_mx.rb +69 -0
- data/lib/adtekio_adnetworks/importers/revenue/lifestreet.rb +59 -0
- data/lib/adtekio_adnetworks/importers/revenue/mdotm.rb +38 -0
- data/lib/adtekio_adnetworks/importers/revenue/mopub.rb +54 -0
- data/lib/adtekio_adnetworks/importers/revenue/nexage.rb +71 -0
- data/lib/adtekio_adnetworks/importers/revenue/supersonic.rb +73 -0
- data/lib/adtekio_adnetworks/importers/revenue/tapsense.rb +38 -0
- data/lib/adtekio_adnetworks/importers/revenue/trialpay.rb +41 -0
- data/lib/adtekio_adnetworks/importers/revenue/vungle.rb +75 -0
- data/lib/adtekio_adnetworks/importers/revenue_import.rb +27 -0
- data/lib/adtekio_adnetworks/postbacks.rb +193 -0
- data/lib/adtekio_adnetworks/postbacks/aarki.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/adaction.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/adcash.rb +19 -0
- data/lib/adtekio_adnetworks/postbacks/adcolony.rb +90 -0
- data/lib/adtekio_adnetworks/postbacks/adgorithms.rb +74 -0
- data/lib/adtekio_adnetworks/postbacks/adjapon_nend.rb +39 -0
- data/lib/adtekio_adnetworks/postbacks/adknowledge.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/admob.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/adp.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/adperio.rb +19 -0
- data/lib/adtekio_adnetworks/postbacks/adquant.rb +39 -0
- data/lib/adtekio_adnetworks/postbacks/adstract.rb +15 -0
- data/lib/adtekio_adnetworks/postbacks/adxperience.rb +16 -0
- data/lib/adtekio_adnetworks/postbacks/airpush.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/app_chocolate.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/appfload.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/appia.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/appintheair.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/applifier.rb +49 -0
- data/lib/adtekio_adnetworks/postbacks/applift.rb +88 -0
- data/lib/adtekio_adnetworks/postbacks/applovin.rb +127 -0
- data/lib/adtekio_adnetworks/postbacks/appnext.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/appredeem.rb +33 -0
- data/lib/adtekio_adnetworks/postbacks/appsfire.rb +19 -0
- data/lib/adtekio_adnetworks/postbacks/appturbo.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/apsalar.rb +21 -0
- data/lib/adtekio_adnetworks/postbacks/bee7.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/bidmotion.rb +80 -0
- data/lib/adtekio_adnetworks/postbacks/blindferretmedia.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/chartboost.rb +116 -0
- data/lib/adtekio_adnetworks/postbacks/cheetah.rb +32 -0
- data/lib/adtekio_adnetworks/postbacks/clickky.rb +30 -0
- data/lib/adtekio_adnetworks/postbacks/covus.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/crossinstall.rb +26 -0
- data/lib/adtekio_adnetworks/postbacks/cyberagent_ameba.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/cyberagent_amoad.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/cyberagent_imobile.rb +43 -0
- data/lib/adtekio_adnetworks/postbacks/cyberagent_kjnw.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/cyberagent_maio.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/cyberagent_nend.rb +40 -0
- data/lib/adtekio_adnetworks/postbacks/cyberagent_smartc.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/cyberagent_smartnews.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/cyberz_asta.rb +26 -0
- data/lib/adtekio_adnetworks/postbacks/cyberz_bead.rb +26 -0
- data/lib/adtekio_adnetworks/postbacks/cyberz_imobile.rb +28 -0
- data/lib/adtekio_adnetworks/postbacks/cyberz_nend.rb +30 -0
- data/lib/adtekio_adnetworks/postbacks/datalead.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/eccrine.rb +80 -0
- data/lib/adtekio_adnetworks/postbacks/eeline.rb +50 -0
- data/lib/adtekio_adnetworks/postbacks/f5.rb +30 -0
- data/lib/adtekio_adnetworks/postbacks/fiksu.rb +43 -0
- data/lib/adtekio_adnetworks/postbacks/fiksu_applift.rb +31 -0
- data/lib/adtekio_adnetworks/postbacks/fractionalmedia.rb +78 -0
- data/lib/adtekio_adnetworks/postbacks/fyber.rb +36 -0
- data/lib/adtekio_adnetworks/postbacks/gamegenetics.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/ginga.rb +26 -0
- data/lib/adtekio_adnetworks/postbacks/glispa.rb +96 -0
- data/lib/adtekio_adnetworks/postbacks/googleadwords.rb +19 -0
- data/lib/adtekio_adnetworks/postbacks/growmobile.rb +36 -0
- data/lib/adtekio_adnetworks/postbacks/heyzap.rb +51 -0
- data/lib/adtekio_adnetworks/postbacks/inmobi.rb +50 -0
- data/lib/adtekio_adnetworks/postbacks/inneractive.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/instal.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/iqu.rb +19 -0
- data/lib/adtekio_adnetworks/postbacks/ironsource.rb +19 -0
- data/lib/adtekio_adnetworks/postbacks/jampp.rb +48 -0
- data/lib/adtekio_adnetworks/postbacks/jestadigital.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/jumpramp.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/jumptap.rb +23 -0
- data/lib/adtekio_adnetworks/postbacks/leadbolt.rb +29 -0
- data/lib/adtekio_adnetworks/postbacks/lifestreet.rb +97 -0
- data/lib/adtekio_adnetworks/postbacks/liftoff.rb +66 -0
- data/lib/adtekio_adnetworks/postbacks/loopme.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/magic_solver.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/marimedia.rb +20 -0
- data/lib/adtekio_adnetworks/postbacks/matomy.rb +59 -0
- data/lib/adtekio_adnetworks/postbacks/mdotm.rb +116 -0
- data/lib/adtekio_adnetworks/postbacks/misterbell.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/mmg.rb +20 -0
- data/lib/adtekio_adnetworks/postbacks/mnectar.rb +22 -0
- data/lib/adtekio_adnetworks/postbacks/moblin.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/moboqo.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/mobpartner.rb +19 -0
- data/lib/adtekio_adnetworks/postbacks/mopub.rb +30 -0
- data/lib/adtekio_adnetworks/postbacks/motive_interactive.rb +32 -0
- data/lib/adtekio_adnetworks/postbacks/mundo.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/nanigans.rb +38 -0
- data/lib/adtekio_adnetworks/postbacks/nativex.rb +30 -0
- data/lib/adtekio_adnetworks/postbacks/neodau.rb +19 -0
- data/lib/adtekio_adnetworks/postbacks/neverblue.rb +19 -0
- data/lib/adtekio_adnetworks/postbacks/operamedia.rb +39 -0
- data/lib/adtekio_adnetworks/postbacks/pandora.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/phunware.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/pirasin.rb +16 -0
- data/lib/adtekio_adnetworks/postbacks/playhaven.rb +31 -0
- data/lib/adtekio_adnetworks/postbacks/pocketmath.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/propeller.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/quixey.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/realzeit.rb +60 -0
- data/lib/adtekio_adnetworks/postbacks/remerge.rb +66 -0
- data/lib/adtekio_adnetworks/postbacks/revmob.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/ripple.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/roostr.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/rtbcom.rb +28 -0
- data/lib/adtekio_adnetworks/postbacks/septeni.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/seven_games.rb +51 -0
- data/lib/adtekio_adnetworks/postbacks/startapp.rb +48 -0
- data/lib/adtekio_adnetworks/postbacks/supersonic.rb +19 -0
- data/lib/adtekio_adnetworks/postbacks/tapjoy.rb +36 -0
- data/lib/adtekio_adnetworks/postbacks/taptica.rb +21 -0
- data/lib/adtekio_adnetworks/postbacks/targetcircle.rb +41 -0
- data/lib/adtekio_adnetworks/postbacks/todacell.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/tokenads.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/trademob.rb +48 -0
- data/lib/adtekio_adnetworks/postbacks/trademob_magic_solver.rb +22 -0
- data/lib/adtekio_adnetworks/postbacks/trialpay.rb +18 -0
- data/lib/adtekio_adnetworks/postbacks/unilead.rb +78 -0
- data/lib/adtekio_adnetworks/postbacks/uppsmobi.rb +19 -0
- data/lib/adtekio_adnetworks/postbacks/vungle.rb +33 -0
- data/lib/adtekio_adnetworks/postbacks/w4.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/webmedia.rb +17 -0
- data/lib/adtekio_adnetworks/postbacks/yahoo.rb +20 -0
- data/lib/adtekio_adnetworks/postbacks/youappi.rb +116 -0
- data/lib/adtekio_adnetworks/postbacks/zemail.rb +19 -0
- data/test/helper.rb +78 -0
- data/test/unit/postbacks/test_chartboost.rb +105 -0
- data/test/unit/postbacks/test_mdotm.rb +35 -0
- data/test/unit/postbacks/test_playhaven.rb +76 -0
- data/test/unit/postbacks/test_trademob_magic_solver.rb +24 -0
- data/test/unit/postbacks/test_unilead.rb +67 -0
- data/test/unit/test_api_key_scrapers.rb +302 -0
- data/test/unit/test_base_postback_class.rb +82 -0
- data/test/unit/test_cost_importers.rb +12 -0
- data/test/unit/test_postbacks.rb +33 -0
- data/test/unit/test_postbacks_definition.rb +111 -0
- data/test/unit/test_revenue_importers.rb +12 -0
- metadata +500 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
class AdtekioAdnetworks::Revenue::Mopub
|
|
2
|
+
include AdtekioAdnetworks::RevenueImport
|
|
3
|
+
|
|
4
|
+
define_required_credentials do
|
|
5
|
+
[:account, :key]
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def revenues(from, to)
|
|
9
|
+
# index meanings can be taken from exp_cols
|
|
10
|
+
report(from,to).map do |row|
|
|
11
|
+
{
|
|
12
|
+
:appname => row[1],
|
|
13
|
+
:date => Date.strptime(row[0], "%Y-%m-%d"),
|
|
14
|
+
:impressions => row[3],
|
|
15
|
+
:requests => row[4].to_i,
|
|
16
|
+
:clicks => row[5],
|
|
17
|
+
:amount => row[6]
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def report(from,to)
|
|
23
|
+
d = data(from,to)
|
|
24
|
+
raise "Columns mismatch: #{d['columns']}" if d['columns'] != exp_cols
|
|
25
|
+
d["rows"]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def exp_cols
|
|
29
|
+
["date", "app", "conversions", "impressions", "attempts",
|
|
30
|
+
"clicks", "revenue"]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def http_client
|
|
34
|
+
Net::HTTP::Persistent.new('chartboost').tap do |h|
|
|
35
|
+
h.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def data(from,to)
|
|
40
|
+
params = {
|
|
41
|
+
:group_by => "date,app",
|
|
42
|
+
:start_date => from.strftime("%Y-%m-%d"),
|
|
43
|
+
:end_date => to.strftime("%Y-%m-%d"),
|
|
44
|
+
:account => credentials.account,
|
|
45
|
+
:key => credentials.key,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
uri = Addressable::URI.new
|
|
49
|
+
uri.query_values = params
|
|
50
|
+
url = URI.parse("%s?%s" % ["https://data-service.mopub.com/mpx",
|
|
51
|
+
uri.query])
|
|
52
|
+
JSON(http_client.request(url).body)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
class AdtekioAdnetworks::Revenue::Nexage
|
|
2
|
+
include AdtekioAdnetworks::RevenueImport
|
|
3
|
+
|
|
4
|
+
define_required_credentials do
|
|
5
|
+
[:company_id, :access_key, :secret_key]
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def revenues(from, to)
|
|
9
|
+
[]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def report(from,to)
|
|
13
|
+
[]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def seller_revenue_by_app(from,to)
|
|
17
|
+
Hash[site_ids(from,to)["detail"].map do |site_data|
|
|
18
|
+
uri = Addressable::URI.new
|
|
19
|
+
uri.query_values = {
|
|
20
|
+
:start => from.strftime("%Y-%m-%d"),
|
|
21
|
+
:stop => to.strftime("%Y-%m-%d"),
|
|
22
|
+
:dim => "day",
|
|
23
|
+
:site => site_data["siteId"]
|
|
24
|
+
}
|
|
25
|
+
url = ("https://reports.nexage.com/access/"+
|
|
26
|
+
"#{credentials.company_id}"+
|
|
27
|
+
"/reports/sellerrevenue")
|
|
28
|
+
|
|
29
|
+
[site_data["site"],
|
|
30
|
+
do_request("%s?%s" % [url, uri.query])["detail"]]
|
|
31
|
+
end]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def site_ids(from,to)
|
|
35
|
+
uri = Addressable::URI.new
|
|
36
|
+
uri.query_values = {
|
|
37
|
+
:start => from.strftime("%Y-%m-%d"),
|
|
38
|
+
:stop => to.strftime("%Y-%m-%d"),
|
|
39
|
+
:dim => "site"
|
|
40
|
+
}
|
|
41
|
+
url = ("https://reports.nexage.com/access/#{credentials.company_id}"+
|
|
42
|
+
"/reports/sellerrevenue")
|
|
43
|
+
do_request("%s?%s" % [url, uri.query])
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def do_request(urlstring)
|
|
47
|
+
digest_auth = Net::HTTP::DigestAuth.new
|
|
48
|
+
|
|
49
|
+
uri = URI.parse(urlstring)
|
|
50
|
+
uri.user = credentials.access_key
|
|
51
|
+
uri.password = credentials.secret_key
|
|
52
|
+
|
|
53
|
+
h = Net::HTTP::Persistent.new('whatever')
|
|
54
|
+
h.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
55
|
+
|
|
56
|
+
req = Net::HTTP::Get.new uri.request_uri
|
|
57
|
+
|
|
58
|
+
res = h.request uri, req
|
|
59
|
+
|
|
60
|
+
auth = digest_auth.auth_header uri, res['www-authenticate'], 'GET'
|
|
61
|
+
|
|
62
|
+
req = Net::HTTP::Get.new uri.request_uri
|
|
63
|
+
req.add_field 'Authorization', auth
|
|
64
|
+
|
|
65
|
+
res = h.request uri,req
|
|
66
|
+
|
|
67
|
+
raise "No data available" if res.code.to_i == 204
|
|
68
|
+
raise "Unable to authenticate" if res.code.to_i != 200
|
|
69
|
+
JSON(res.body)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
class AdtekioAdnetworks::Revenue::Supersonic
|
|
2
|
+
include AdtekioAdnetworks::RevenueImport
|
|
3
|
+
|
|
4
|
+
BASE_URL = "https://api.supersonicads.com/api/rest/v1/ultra/statistics"
|
|
5
|
+
|
|
6
|
+
define_required_credentials do
|
|
7
|
+
[:access_key, :secret_key]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def revenues(from, to)
|
|
11
|
+
report(from,to).map do |(appname, appid, providerName, date), values|
|
|
12
|
+
values.map do |dpt|
|
|
13
|
+
# we assume: impressions == clicks, strange but true!
|
|
14
|
+
if dpt.impressions != dpt.clicks
|
|
15
|
+
raise "impressions didn't match clicks: "+
|
|
16
|
+
"#{dpt.impressions}/#{dpt.clicks}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
nmstuff = {
|
|
20
|
+
:provider => providerName,
|
|
21
|
+
:appid => appid,
|
|
22
|
+
:uniqUser => dpt.uniqueUsers.remove(',').to_i,
|
|
23
|
+
:uniqPayingUsers => dpt.uniquePayingUsers.remove(',').to_i,
|
|
24
|
+
:rewards => dpt.rewards.remove(',').to_i,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
{
|
|
28
|
+
:date => Date.strptime(date, "%Y-%m-%d"),
|
|
29
|
+
:appname => appname,
|
|
30
|
+
:amount => dpt.revenue.remove('$').to_f,
|
|
31
|
+
:requests => dpt.hits.remove(',').to_i,
|
|
32
|
+
:impressions => dpt.fulfillments.remove(',').to_i,
|
|
33
|
+
:clicks => dpt.clicks.remove(',').to_i,
|
|
34
|
+
:completions => dpt.completions.remove(',').to_i,
|
|
35
|
+
:not_matched => not_matched(nmstuff)
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
end.flatten
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def report(from,to)
|
|
42
|
+
CSV(ultra_data(from,to), :col_sep => ",", :headers => true ).map do |a|
|
|
43
|
+
OpenStruct.new(a.to_h)
|
|
44
|
+
end[0..-2].group_by do |a| ## last line is a summary row, ignore it.
|
|
45
|
+
[a.applicationName, a.applicationId, a.providerName, a.theDate]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def http_client
|
|
50
|
+
@http_client ||= Net::HTTP::Persistent.new('supersonic').tap do |client|
|
|
51
|
+
client.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def ultra_data(from_date, to_date)
|
|
56
|
+
http_client.request(ultra_url(from_date, to_date)).body
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def ultra_url(from_date, to_date)
|
|
60
|
+
uri = Addressable::URI.new
|
|
61
|
+
uri.query_values = {
|
|
62
|
+
:accessKey => credentials.access_key,
|
|
63
|
+
:secretKey => credentials.secret_key,
|
|
64
|
+
:onlyRevenue => 0,
|
|
65
|
+
:fromDate => from_date.strftime("%Y-%m-%d"),
|
|
66
|
+
:toDate => to_date.strftime("%Y-%m-%d"),
|
|
67
|
+
:format => "csv",
|
|
68
|
+
"breakdowns[]" => ["date", "application", "provider"]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
URI.parse("%s?%s" % [BASE_URL, uri.query])
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
class AdtekioAdnetworks::Revenue::Tapsense
|
|
2
|
+
include AdtekioAdnetworks::RevenueImport
|
|
3
|
+
## More info on the API:
|
|
4
|
+
## https://github.com/TapSense/tapsense-adapters/wiki/TapSense-Reporting-API-for-Publishers
|
|
5
|
+
|
|
6
|
+
define_required_credentials do
|
|
7
|
+
[:username, :password]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def revenues(from, to)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def report(from,to)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def data(from, to)
|
|
17
|
+
require 'mechanize'
|
|
18
|
+
agent = Mechanize.new
|
|
19
|
+
agent.user_agent_alias = 'Mac Safari'
|
|
20
|
+
|
|
21
|
+
agent.post("https://dashboard.tapsense.com/console/login", {
|
|
22
|
+
:username => credentials.username,
|
|
23
|
+
:password => credentials.password}.to_json,
|
|
24
|
+
{"Content-Type" => "application/json",
|
|
25
|
+
"Accept" => "application/json" })
|
|
26
|
+
|
|
27
|
+
uri = Addressable::URI.new
|
|
28
|
+
uri.query_values = {
|
|
29
|
+
:start_date => from.strftime("%Y-%m-%d"),
|
|
30
|
+
:end_date => to.strftime("%Y-%m-%d"),
|
|
31
|
+
:format => :json,
|
|
32
|
+
:rollup => "date,country",
|
|
33
|
+
:action_type => "report"
|
|
34
|
+
}
|
|
35
|
+
url = "https://dashboard.tapsense.com/console/publisher/report"
|
|
36
|
+
agent.get("%s?%s" % [url, uri.query]).body
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
class AdtekioAdnetworks::Revenue::Trialpay
|
|
2
|
+
include AdtekioAdnetworks::RevenueImport
|
|
3
|
+
|
|
4
|
+
define_required_credentials do
|
|
5
|
+
[:username, :password]
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def revenues(from, to)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def report(from,to)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def dailysummary
|
|
15
|
+
require 'mechanize'
|
|
16
|
+
agent = Mechanize.new
|
|
17
|
+
agent.user_agent_alias = 'Mac Safari'
|
|
18
|
+
|
|
19
|
+
agent.post("https://merchant.trialpay.com/login/", {
|
|
20
|
+
:action => "del",
|
|
21
|
+
:email => credentials.username,
|
|
22
|
+
:password => credentials.password})
|
|
23
|
+
|
|
24
|
+
uri = Addressable::URI.new
|
|
25
|
+
uri.query_values = {
|
|
26
|
+
:app_id => "",
|
|
27
|
+
:context => "",
|
|
28
|
+
:group_by => "group_by_app_id_context_and_date",
|
|
29
|
+
:date_group => "day",
|
|
30
|
+
:date_type => 1,
|
|
31
|
+
:date_interval => 6, # 30 days back
|
|
32
|
+
:csv => "Export to CSV",
|
|
33
|
+
"[sort_by]" => "date",
|
|
34
|
+
"[sort_order]" => "asc",
|
|
35
|
+
"report_table[sort_by]" => "date",
|
|
36
|
+
"report_table[sort_order]" => "asc",
|
|
37
|
+
}
|
|
38
|
+
url = "https://merchant.trialpay.com/reports/dailysummary/"
|
|
39
|
+
agent.get("%s?%s" % [url, uri.query]).body
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
class AdtekioAdnetworks::Revenue::Vungle
|
|
2
|
+
include AdtekioAdnetworks::RevenueImport
|
|
3
|
+
|
|
4
|
+
BASE_URL = "https://ssl.vungle.com"
|
|
5
|
+
|
|
6
|
+
define_required_credentials do
|
|
7
|
+
[:api_key]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def revenues(from, to)
|
|
11
|
+
report(from,to).map do |dpt|
|
|
12
|
+
nmstuff = {
|
|
13
|
+
:appId => dpt['appId'],
|
|
14
|
+
:installs => dpt['installs'],
|
|
15
|
+
:platform => dpt['platform'],
|
|
16
|
+
:status => dpt['status'],
|
|
17
|
+
:connection => dpt['connection']
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
{
|
|
21
|
+
:appname => dpt['name'],
|
|
22
|
+
:date => dpt['datestamp'],
|
|
23
|
+
:amount => dpt['revenue'].to_f,
|
|
24
|
+
:impressions => dpt['impressions'].to_i,
|
|
25
|
+
:clicks => dpt['views'].to_i,
|
|
26
|
+
:completions => dpt['completes'].to_i,
|
|
27
|
+
:not_matched => not_matched(nmstuff)
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def report(from,to)
|
|
33
|
+
# Because we have a api rate limit of 2 per 10 seconds:
|
|
34
|
+
# ApiError: Rate limit hit. Maximum 2 requests every 10 seconds
|
|
35
|
+
# batch the dates together and sleep 5 seconds between requests.
|
|
36
|
+
applications.map do |app|
|
|
37
|
+
sleep 5
|
|
38
|
+
retrieve_data(app["id"], from, to).map do |data|
|
|
39
|
+
data.merge(app).
|
|
40
|
+
merge("datestamp" => Date.strptime(data["date"], "%Y-%m-%d"))
|
|
41
|
+
end
|
|
42
|
+
end.flatten
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def applications
|
|
46
|
+
uri = Addressable::URI.new
|
|
47
|
+
uri.query_values = { :key => credentials.api_key }
|
|
48
|
+
datauri = URI.
|
|
49
|
+
parse("%s/api/applications?%s" % [BASE_URL, uri.query])
|
|
50
|
+
|
|
51
|
+
JSON(Net::HTTP::Persistent.new('vungle').request(datauri).body)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def retrieve_data(app, startdate, enddate)
|
|
55
|
+
uri = Addressable::URI.new
|
|
56
|
+
uri.query_values = {
|
|
57
|
+
:key => credentials.api_key,
|
|
58
|
+
:start => startdate.strftime("%Y-%m-%d"),
|
|
59
|
+
:end => enddate.strftime("%Y-%m-%d")
|
|
60
|
+
}
|
|
61
|
+
datauri = URI.
|
|
62
|
+
parse("%s/api/applications/%s?%s" % [BASE_URL, app, uri.query])
|
|
63
|
+
|
|
64
|
+
json_data_string =
|
|
65
|
+
Net::HTTP::Persistent.new('vungle').request(datauri).body
|
|
66
|
+
|
|
67
|
+
begin
|
|
68
|
+
JSON(json_data_string)
|
|
69
|
+
rescue Exception => e
|
|
70
|
+
$stderr.puts("vungle data failure: #{e}")
|
|
71
|
+
$stderr.puts("json data string: #{json_data_string}")
|
|
72
|
+
[]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module AdtekioAdnetworks
|
|
2
|
+
module Revenue
|
|
3
|
+
# placeholder
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
module RevenueImport
|
|
7
|
+
include BaseImporter
|
|
8
|
+
|
|
9
|
+
def check_version!(version, expected_version)
|
|
10
|
+
raise "Unsupported version: #{version}" if version != expected_version
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def check_currency!(currency, expected_currency)
|
|
14
|
+
raise "Unsupported currency: #{currency}" if currency != expected_currency
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def not_matched(hsh)
|
|
18
|
+
uri = Addressable::URI.new
|
|
19
|
+
uri.query_values = hsh
|
|
20
|
+
uri.query
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
Dir[File.join(File.dirname(__FILE__), 'revenue', '*.rb')].each do |f|
|
|
26
|
+
require f
|
|
27
|
+
end
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
require 'uuidtools'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'digest/sha2'
|
|
4
|
+
require 'digest/md5'
|
|
5
|
+
require 'erubis'
|
|
6
|
+
require 'active_support'
|
|
7
|
+
require 'active_support/core_ext'
|
|
8
|
+
|
|
9
|
+
module AdtekioAdnetworks
|
|
10
|
+
module Postbacks
|
|
11
|
+
extend self
|
|
12
|
+
|
|
13
|
+
PossibleEvents = {
|
|
14
|
+
:mac => "Attribution",
|
|
15
|
+
:ist => "Application Install",
|
|
16
|
+
:apo => "Application Open",
|
|
17
|
+
:fun => "Tutorial",
|
|
18
|
+
:pay => "Payment",
|
|
19
|
+
:eor => "End of Round",
|
|
20
|
+
:scs => "Scene Start",
|
|
21
|
+
:scc => "Scene Complete",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def networks
|
|
25
|
+
@networks ||= {}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def register(postback_klz)
|
|
29
|
+
networks[postback_klz.network] = postback_klz
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class BasePostbackClass
|
|
34
|
+
attr_reader :event, :params, :user, :netcfg
|
|
35
|
+
|
|
36
|
+
class CGIEruby < Erubis::PI::Eruby
|
|
37
|
+
REGEXP = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]").freeze
|
|
38
|
+
|
|
39
|
+
def escaped_expr(code)
|
|
40
|
+
"URI.encode((#{code.strip}).to_s, CGIEruby::REGEXP)"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class MD5 < Digest::MD5
|
|
45
|
+
class << self
|
|
46
|
+
alias orig_new new
|
|
47
|
+
def new(str = nil)
|
|
48
|
+
str ? orig_new.update(str) : orig_new
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def md5(*args)
|
|
52
|
+
new(*args)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def initialize(event, user, netcfg, params = nil)
|
|
58
|
+
@event = event
|
|
59
|
+
@params = params || (event && event.params)
|
|
60
|
+
@user = user
|
|
61
|
+
@netcfg = netcfg
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def sha1(value)
|
|
65
|
+
Digest::SHA1.hexdigest(value || "")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def muidify(val)
|
|
69
|
+
Base64.encode64(MD5.md5(val).digest).tr("+/=", "-_\n").strip
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def contains_eruby?(val)
|
|
73
|
+
val && !!(val =~ /@\{.*\}@/ || val =~ /<%.*%>/m)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def parse_string(str)
|
|
77
|
+
contains_eruby?(str) ? CGIEruby.new(str).result(binding) : str
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def should_handle?(cfg)
|
|
81
|
+
cfg.check.nil? ||
|
|
82
|
+
!!(cfg.check.is_a?(Symbol) ? send(cfg.check) : eval(cfg.check))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def either_hash_or_symbol_to_string(val)
|
|
86
|
+
if val.is_a?(Hash)
|
|
87
|
+
uri = Addressable::URI.new
|
|
88
|
+
uri.query_values = val
|
|
89
|
+
CGI.unescape(uri.to_s).gsub(/^[?]/,'')
|
|
90
|
+
elsif val.is_a?(Symbol)
|
|
91
|
+
send(val)
|
|
92
|
+
else
|
|
93
|
+
val.to_s
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def cfg_to_url(cfg)
|
|
98
|
+
return unless should_handle?(cfg)
|
|
99
|
+
|
|
100
|
+
header = either_hash_or_symbol_to_string(cfg.header)
|
|
101
|
+
body = either_hash_or_symbol_to_string(cfg.post)
|
|
102
|
+
|
|
103
|
+
urlparams = ( (cfg.params.is_a?(Hash) && cfg.params) ||
|
|
104
|
+
cfg.params.is_a?(Symbol) && send(cfg.params) ) || {}
|
|
105
|
+
|
|
106
|
+
uri = Addressable::URI.parse(cfg.url)
|
|
107
|
+
uri.query_values = urlparams unless urlparams.empty?
|
|
108
|
+
url = CGI.unescape(uri.to_s)
|
|
109
|
+
|
|
110
|
+
parsed_header = CGI::parse(parse_string(header) || "")
|
|
111
|
+
parsed_header.each { |key, value| parsed_header[key] = value.first }
|
|
112
|
+
|
|
113
|
+
{ :url => parse_string(url),
|
|
114
|
+
:body => parse_string(body),
|
|
115
|
+
:header => parsed_header}
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
module BasePostbacks
|
|
120
|
+
def self.included(klz)
|
|
121
|
+
klz.class_eval do
|
|
122
|
+
def self.postbacks
|
|
123
|
+
@postbacks ||= Hash.new{ |k,v| k[v] = [] }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def self.pbcfg
|
|
127
|
+
@pbcfg ||= Hash.new{ |k,v| k[v] = Hash.new{ |k,v| k[v] = [] }}
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def self.define_network_config(&block)
|
|
131
|
+
@network_config = yield
|
|
132
|
+
self.class_eval do
|
|
133
|
+
def self.netcfg
|
|
134
|
+
@network_config
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def self.define_postback_for(platform, type, &block)
|
|
140
|
+
cfg = OpenStruct.new(yield)
|
|
141
|
+
|
|
142
|
+
postbacks[platform] << type.to_sym
|
|
143
|
+
pbcfg[platform][type.to_sym] << cfg
|
|
144
|
+
|
|
145
|
+
self.send(:define_method, type, Proc.new do |platform|
|
|
146
|
+
pbc = self.class.instance_variable_get("@pbcfg")
|
|
147
|
+
pbc[platform.to_sym][type.to_sym].map do |cfg|
|
|
148
|
+
cfg_to_url(cfg)
|
|
149
|
+
end.compact
|
|
150
|
+
end)
|
|
151
|
+
|
|
152
|
+
self.class.send(:define_method, type, Proc.new do |platform|
|
|
153
|
+
@pbcfg[platform.to_sym][type.to_sym].map do |cfg|
|
|
154
|
+
cfg_to_description(cfg)
|
|
155
|
+
end
|
|
156
|
+
end)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def self.cfg_to_description(cfg)
|
|
160
|
+
url = if cfg.params.is_a?(Hash)
|
|
161
|
+
uri = Addressable::URI.parse(cfg.url)
|
|
162
|
+
uri.query_values = cfg.params unless cfg.params.empty?
|
|
163
|
+
CGI.unescape(uri.to_s)
|
|
164
|
+
else
|
|
165
|
+
"%s?%s" % [cfg.url, cfg.params.to_s]
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
{ :url => url,
|
|
169
|
+
:user_required => cfg.user_required || false,
|
|
170
|
+
:store_user => cfg.store_user || false }
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def self.user_required?(event, platform)
|
|
174
|
+
self.send(event, platform).any? { |desc| desc[:user_required] }
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def self.store_user?(event, platform)
|
|
178
|
+
self.send(event, platform).any? { |desc| desc[:store_user] }
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def self.network
|
|
182
|
+
name.to_s.sub(/^.+::([^:]+)$/,'\1').snakecase.to_sym
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
Postbacks.register(klz)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
Dir[File.join(File.dirname(__FILE__), 'postbacks', '*.rb')].each do |f|
|
|
192
|
+
require f
|
|
193
|
+
end
|