mountain-goat 0.1.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +119 -48
- data/generators/mg/mg_generator.rb +17 -9
- data/generators/mg/templates/create_mountain_goat_tables.rb +61 -25
- data/generators/mg/templates/mg.rb +1 -0
- data/generators/mg/templates/mountain-goat.yml +22 -3
- data/generators/mg/templates/mountain_goat_reports.rake +17 -0
- data/generators/mg/templates/update_mountain_goat_tables.rb +104 -0
- data/lib/mountain-goat.rb +21 -12
- data/lib/mountain-goat/analytics.rb +134 -0
- data/lib/mountain-goat/controllers/{mountain_goat/mountain_goat_converts_controller.rb → mg/converts_controller.rb} +12 -11
- data/lib/mountain-goat/controllers/{mountain_goat/mountain_goat_metric_variants_controller.rb → mg/metric_variants_controller.rb} +6 -5
- data/lib/mountain-goat/controllers/{mountain_goat/mountain_goat_metrics_controller.rb → mg/metrics_controller.rb} +8 -6
- data/lib/mountain-goat/controllers/mg/mg.rb +47 -0
- data/lib/mountain-goat/controllers/{mountain_goat → mg}/mountain_goat_controller.rb +5 -42
- data/lib/mountain-goat/controllers/mg/playground_controller.rb +8 -0
- data/lib/mountain-goat/controllers/{mountain_goat/mountain_goat_rallies_controller.rb → mg/rallies_controller.rb} +4 -26
- data/lib/mountain-goat/controllers/mg/report_items_controller.rb +82 -0
- data/lib/mountain-goat/controllers/mg/reports_controller.rb +90 -0
- data/lib/mountain-goat/m_g.rb +64 -0
- data/lib/mountain-goat/metric_tracking.rb +192 -74
- data/lib/mountain-goat/models/mg/ci_meta.rb +10 -0
- data/lib/mountain-goat/models/mg/convert.rb +147 -0
- data/lib/mountain-goat/models/mg/convert_meta_type.rb +20 -0
- data/lib/mountain-goat/models/mg/cs_meta.rb +10 -0
- data/lib/mountain-goat/models/{metric.rb → mg/metric.rb} +3 -5
- data/lib/mountain-goat/models/mg/metric_variant.rb +25 -0
- data/lib/mountain-goat/models/mg/mountain_goat.rb +3 -0
- data/lib/mountain-goat/models/{rally.rb → mg/rally.rb} +4 -3
- data/lib/mountain-goat/models/mg/report.rb +11 -0
- data/lib/mountain-goat/models/mg/report_item.rb +24 -0
- data/lib/mountain-goat/models/mg/report_mailer.rb +18 -0
- data/lib/mountain-goat/public/g-bar-min.js +7 -0
- data/lib/mountain-goat/public/g-dot-min.js +7 -0
- data/lib/mountain-goat/public/g-line-min.js +7 -0
- data/lib/mountain-goat/public/g-pie-min.js +1 -0
- data/lib/mountain-goat/public/g-raphael-min.js +7 -0
- data/lib/mountain-goat/public/jqModel.css +41 -0
- data/lib/mountain-goat/public/jqModel.js +69 -0
- data/lib/mountain-goat/public/jquery.raphael.js +208 -0
- data/lib/mountain-goat/public/mg.css +135 -26
- data/lib/mountain-goat/public/mg.js +53 -1
- data/lib/mountain-goat/public/raphael-min.js +7 -0
- data/lib/mountain-goat/public/utils.js +520 -0
- data/lib/mountain-goat/switch_variant.rb +4 -4
- data/lib/mountain-goat/version.rb +1 -1
- data/lib/mountain-goat/views/mountain_goat/layouts/_pdf.html.erb +15 -0
- data/lib/mountain-goat/views/mountain_goat/layouts/mountain_goat.html.erb +17 -5
- data/lib/mountain-goat/views/mountain_goat/layouts/xhr.html.erb +2 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_converts → mg/converts}/.tmp_show.html.erb.4433~ +0 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_converts → mg/converts}/_convert_form.html.erb +0 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_converts → mg/converts}/_convert_meta_type_form.html.erb +0 -0
- data/lib/mountain-goat/views/mountain_goat/mg/converts/edit.html.erb +13 -0
- data/lib/mountain-goat/views/mountain_goat/mg/converts/index.html.erb +25 -0
- data/lib/mountain-goat/views/mountain_goat/mg/converts/new.html.erb +13 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_converts → mg/converts}/show.html.erb +3 -28
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_metric_variants → mg/metric_variants}/_metric_variant_form.html.erb +0 -4
- data/lib/mountain-goat/views/mountain_goat/mg/metric_variants/edit.html.erb +13 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_metric_variants → mg/metric_variants}/index.html.erb +3 -3
- data/lib/mountain-goat/views/mountain_goat/mg/metric_variants/new.html.erb +15 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_metric_variants → mg/metric_variants}/show.html.erb +4 -5
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_metrics → mg/metrics}/.tmp_show.html.erb.21270~ +0 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_metrics → mg/metrics}/_metric_form.html.erb +0 -2
- data/lib/mountain-goat/views/mountain_goat/mg/metrics/edit.html.erb +13 -0
- data/lib/mountain-goat/views/mountain_goat/mg/metrics/index.html.erb +14 -0
- data/lib/mountain-goat/views/mountain_goat/mg/metrics/new.html.erb +14 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_metrics → mg/metrics}/show.html.erb +7 -8
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat → mg/mountain_goat}/login.html.erb +0 -0
- data/lib/mountain-goat/views/mountain_goat/mg/playground/test.html.erb +14 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_rallies → mg/rallies}/.tmp__rally.html.erb.40484~ +0 -0
- data/lib/mountain-goat/views/mountain_goat/mg/rallies/_rallies.html.erb +5 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_rallies → mg/rallies}/_rallies_form.html.erb +0 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_rallies → mg/rallies}/_rally.html.erb +0 -0
- data/lib/mountain-goat/views/mountain_goat/mg/rallies/edit.html.erb +13 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_rallies → mg/rallies}/index.html.erb +1 -1
- data/lib/mountain-goat/views/mountain_goat/mg/rallies/new.html.erb +13 -0
- data/lib/mountain-goat/views/mountain_goat/{mountain_goat_rallies → mg/rallies}/show.html.erb +1 -1
- data/lib/mountain-goat/views/mountain_goat/mg/report_items/_chart.html.erb +18 -0
- data/lib/mountain-goat/views/mountain_goat/mg/report_items/_report_item_form.html.erb +10 -0
- data/lib/mountain-goat/views/mountain_goat/mg/report_items/_report_item_pivot_form.html.erb +14 -0
- data/lib/mountain-goat/views/mountain_goat/mg/report_items/_show.html.erb +29 -0
- data/lib/mountain-goat/views/mountain_goat/mg/report_items/_svg_chart.html.erb +4 -0
- data/lib/mountain-goat/views/mountain_goat/mg/report_items/edit.html.erb +19 -0
- data/lib/mountain-goat/views/mountain_goat/mg/report_items/new.html.erb +17 -0
- data/lib/mountain-goat/views/mountain_goat/mg/report_mailer/report.html.erb +27 -0
- data/lib/mountain-goat/views/mountain_goat/mg/reports/_report.html.erb +22 -0
- data/lib/mountain-goat/views/mountain_goat/mg/reports/_report_form.html.erb +21 -0
- data/lib/mountain-goat/views/mountain_goat/mg/reports/_report_report_items.html.erb +5 -0
- data/lib/mountain-goat/views/mountain_goat/mg/reports/edit.html.erb +36 -0
- data/lib/mountain-goat/views/mountain_goat/mg/reports/index.html.erb +26 -0
- data/lib/mountain-goat/views/mountain_goat/mg/reports/new.html.erb +17 -0
- data/lib/mountain-goat/views/mountain_goat/mg/reports/show.html.erb +21 -0
- data/test/fixtures/{ci_metas.yml → mg_ci_metas.yml} +0 -0
- data/test/fixtures/{convert_meta_types.yml → mg_convert_meta_types.yml} +0 -0
- data/test/fixtures/{converts.yml → mg_converts.yml} +5 -0
- data/test/fixtures/{cs_metas.yml → mg_cs_metas.yml} +0 -0
- data/test/fixtures/mg_deliveries.yml +9 -0
- data/test/fixtures/{metric_variants.yml → mg_metric_variants.yml} +0 -0
- data/test/fixtures/{metrics.yml → mg_metrics.yml} +2 -3
- data/test/fixtures/{rallies.yml → mg_rallies.yml} +6 -2
- data/test/fixtures/mg_report_items.yml +13 -0
- data/test/fixtures/mg_reports.yml +15 -0
- data/test/mg_convert_test.rb +32 -0
- data/test/mg_converts_controller_test.rb +47 -0
- data/test/mg_metric_variants_controller_test.rb +46 -0
- data/test/mg_metrics_controller_test.rb +52 -0
- data/test/mg_mountain_goat_controller_test.rb +45 -0
- data/test/mg_mountain_goat_test.rb +392 -0
- data/test/mg_playground_controller_test.rb +11 -0
- data/test/mg_rallies_controller_test.rb +36 -0
- data/test/mg_report_item_test.rb +7 -0
- data/test/mg_report_items_controller_test.rb +31 -0
- data/test/mg_report_test.rb +18 -0
- data/test/mg_reports_controller_test.rb +50 -0
- data/test/test_helper.rb +203 -0
- metadata +108 -55
- data/lib/mountain-goat/models/ci_meta.rb +0 -9
- data/lib/mountain-goat/models/convert.rb +0 -70
- data/lib/mountain-goat/models/convert_meta_type.rb +0 -19
- data/lib/mountain-goat/models/cs_meta.rb +0 -9
- data/lib/mountain-goat/models/metric_variant.rb +0 -22
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_converts/edit.html.erb +0 -13
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_converts/index.html.erb +0 -48
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_converts/new.html.erb +0 -13
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_metric_variants/edit.html.erb +0 -13
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_metric_variants/new.html.erb +0 -15
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_metrics/edit.html.erb +0 -13
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_metrics/index.html.erb +0 -14
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_metrics/new.html.erb +0 -14
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/_rallies.html.erb +0 -5
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/edit.html.erb +0 -13
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/new.html.erb +0 -13
- data/test/ocelot_converts_controller_test.rb +0 -45
- data/test/ocelot_metric_variants_controller_test.rb +0 -45
- data/test/ocelot_metrics_controller_test.rb +0 -45
- data/test/ocelot_rallies_controller_test.rb +0 -8
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
class Mg < ActionController::Base
|
3
|
+
|
4
|
+
layout 'mountain_goat'
|
5
|
+
|
6
|
+
before_filter :verify_access
|
7
|
+
|
8
|
+
self.prepend_view_path File.join([File.dirname(__FILE__), '../../views/mountain_goat/'])
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def store_location(url = nil)
|
13
|
+
if url.nil?
|
14
|
+
if request.method == :post && request.params.count > 0
|
15
|
+
session[:mg_return_to] = "#{request.request_uri}?" + encode_parameters(request.params)
|
16
|
+
else
|
17
|
+
session[:mg_return_to] = request.request_uri
|
18
|
+
end
|
19
|
+
else
|
20
|
+
session[:mg_return_to] = url
|
21
|
+
end
|
22
|
+
|
23
|
+
logger.warn "Storing location: #{session[:mg_return_to]}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def redirect_back_or_default(default)
|
27
|
+
redirect_to(session[:mg_return_to] || default)
|
28
|
+
session[:mg_return_to] = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def verify_access
|
32
|
+
return if session[:mg_access] == true
|
33
|
+
store_location
|
34
|
+
redirect_to mg_login_url and return
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.password_digest(password, salt)
|
38
|
+
site_key = '1e9532ea39233e1e2786d80fde90d708c0918d2d'
|
39
|
+
stretches = 10
|
40
|
+
digest = site_key
|
41
|
+
stretches.times do
|
42
|
+
digest = secure_digest(digest, salt, password, site_key)
|
43
|
+
end
|
44
|
+
digest
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -1,15 +1,14 @@
|
|
1
1
|
|
2
|
-
class MountainGoatController <
|
3
|
-
|
4
|
-
layout 'mountain_goat'
|
2
|
+
class Mg::MountainGoatController < Mg
|
5
3
|
|
6
4
|
before_filter :verify_access, :except => [ :login, :login_create, :fetch ]
|
7
|
-
|
8
|
-
self.prepend_view_path File.join([File.dirname(__FILE__), '../../views/mountain_goat/'])
|
9
5
|
|
10
6
|
def fetch
|
11
7
|
ct = { :png => 'image/png', :css => 'text/css', :html => 'text/html', :js => 'text/javascript' }
|
12
8
|
|
9
|
+
raise ArgumentError, "Invalid fetch file" if params[:file].match(/(([_][_])|([^a-z0-9_]))/ix) #extra security
|
10
|
+
|
11
|
+
#We will only serve files located in the public directory for security reasons
|
13
12
|
Dir.open(File.join([File.dirname(__FILE__), '../../public/'])).each do |file|
|
14
13
|
if file == params[:file].gsub('_','.')
|
15
14
|
if file =~ /[.]([a-z0-9]+)$/
|
@@ -21,13 +20,7 @@ class MountainGoatController < ActionController::Base
|
|
21
20
|
end
|
22
21
|
end
|
23
22
|
|
24
|
-
render :file => "#{
|
25
|
-
end
|
26
|
-
|
27
|
-
def verify_access
|
28
|
-
return if session.has_key?(:mg_access) && session[:mg_access] == true
|
29
|
-
store_location
|
30
|
-
redirect_to '/mg/login' and return
|
23
|
+
render :file => "#{RAILS_ROOT}/public/404.html", :status => :not_found
|
31
24
|
end
|
32
25
|
|
33
26
|
def login
|
@@ -70,34 +63,4 @@ class MountainGoatController < ActionController::Base
|
|
70
63
|
end
|
71
64
|
end
|
72
65
|
|
73
|
-
def store_location(url = nil)
|
74
|
-
if url.nil?
|
75
|
-
if request.method == :post && request.params.count > 0
|
76
|
-
session[:mg_return_to] = "#{request.request_uri}?" + encode_parameters(request.params)
|
77
|
-
else
|
78
|
-
session[:mg_return_to] = request.request_uri
|
79
|
-
end
|
80
|
-
else
|
81
|
-
session[:mg_return_to] = url
|
82
|
-
end
|
83
|
-
|
84
|
-
logger.warn "Storing location: #{session[:mg_return_to]}"
|
85
|
-
end
|
86
|
-
|
87
|
-
def redirect_back_or_default(default)
|
88
|
-
redirect_to(session[:mg_return_to] || default)
|
89
|
-
session[:mg_return_to] = nil
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
93
|
-
|
94
|
-
def self.password_digest(password, salt)
|
95
|
-
site_key = '1e9532ea39233e1e2786d80fde90d708c0918d2d'
|
96
|
-
stretches = 10
|
97
|
-
digest = site_key
|
98
|
-
stretches.times do
|
99
|
-
digest = secure_digest(digest, salt, password, site_key)
|
100
|
-
end
|
101
|
-
digest
|
102
|
-
end
|
103
66
|
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
class Mg::RalliesController < Mg
|
2
3
|
|
3
4
|
def index
|
4
|
-
|
5
5
|
@page = !params[:page].nil? ? params[:page].to_i : 1
|
6
|
-
@convert = Convert.find(params[:
|
6
|
+
@convert = Convert.find(params[:convert_id]) if !params[:convert_id].nil?
|
7
7
|
|
8
8
|
if @convert
|
9
9
|
@rallies = @convert.rallies.find(:all, :conditions => { }, :order => "created_at DESC", :limit => 100, :offset => ( @page - 1 ) * 100 )
|
@@ -28,7 +28,7 @@ class MountainGoatRalliesController < MountainGoatController
|
|
28
28
|
|
29
29
|
if @rallies.count > 0
|
30
30
|
render :json => { :success => true,
|
31
|
-
:result => render_to_string(:partial => '
|
31
|
+
:result => render_to_string(:partial => 'mg/rallies/rallies', :locals => { :rallies => @rallies } ),
|
32
32
|
:recent_rally_id => @rallies.first.id }
|
33
33
|
else
|
34
34
|
render :json => { :success => false }
|
@@ -40,26 +40,4 @@ class MountainGoatRalliesController < MountainGoatController
|
|
40
40
|
@rally = Rally.find(params[:id])
|
41
41
|
end
|
42
42
|
|
43
|
-
def new
|
44
|
-
if params[:convert_id]
|
45
|
-
@rally = Rally.new(:convert_id => params[:convert_id])
|
46
|
-
else
|
47
|
-
@rally = Rally.new
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
def create
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
def edit
|
57
|
-
@rally = Rally.find(params[:id])
|
58
|
-
end
|
59
|
-
|
60
|
-
def update
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
|
65
43
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
class Mg::ReportItemsController < Mg
|
2
|
+
|
3
|
+
def get_extra
|
4
|
+
( render :json => { :success => true, :result => "<span></span>" } and return ) if params[:value].blank?
|
5
|
+
id, model = params[:value].split('-')
|
6
|
+
reportable = model.constantize.find(id)
|
7
|
+
render :json => { :success => true, :result => render_to_string( :partial => 'mg/report_items/report_item_pivot_form', :locals => { :reportable => reportable } ) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def new
|
11
|
+
@report = Mg::Report.find(params[:report_id])
|
12
|
+
raise ArgumentError, "Invalid report" if @report.nil?
|
13
|
+
|
14
|
+
@report_item = Mg::ReportItem.new
|
15
|
+
|
16
|
+
render :json => { :success => true,
|
17
|
+
:result => render_to_string(:action => :new, :layout => 'xhr') }
|
18
|
+
end
|
19
|
+
|
20
|
+
def create
|
21
|
+
@report = Mg::Report.find(params[:report_id])
|
22
|
+
raise ArgumentError, "Invalid report" if @report.nil?
|
23
|
+
|
24
|
+
@report_item = @report.report_items.new(params[:report_item].clone.delete_if { |k, v| k.intern == :reportable || k.intern == :pivot } )
|
25
|
+
@report_item.order = @report.report_items.to_a.map { |ri| ri.order }.push(0).max + 1#@report.report_items.maximum(:order) + 1 -- weird sqlite3 bugs
|
26
|
+
|
27
|
+
if !params[:report_item][:reportable].blank?
|
28
|
+
id, model = params[:report_item][:reportable].split('-')
|
29
|
+
@report_item.reportable = model.constantize.find(id)
|
30
|
+
end
|
31
|
+
|
32
|
+
if !params[:report_item][:pivot].blank?
|
33
|
+
id, model = params[:report_item][:pivot].split('-')
|
34
|
+
@report_item.pivot = model.constantize.find(id)
|
35
|
+
end
|
36
|
+
|
37
|
+
if @report_item.save
|
38
|
+
render :json => { :success => true,
|
39
|
+
:close_dialog => true,
|
40
|
+
:result => "<span>Successfully added report item</span>",
|
41
|
+
:also => [ { :item => ".report-report-items", :result => render_to_string( :partial => "mg/reports/report_report_items", :locals => { :report => @report_item.report } ) } ] }
|
42
|
+
else
|
43
|
+
render :json => { :success => true,
|
44
|
+
:result => render_to_string(:action => :new, :layout => 'xhr') }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def edit
|
49
|
+
@report_item = Mg::ReportItem.find(params[:id])
|
50
|
+
@report = @report_item.report
|
51
|
+
|
52
|
+
render :json => { :success => true,
|
53
|
+
:result => render_to_string(:action => :edit, :layout => 'xhr') }
|
54
|
+
end
|
55
|
+
|
56
|
+
def update
|
57
|
+
@report_item = Mg::ReportItem.find(params[:id])
|
58
|
+
@report_item.update_attributes(params[:report_item].clone.delete_if { |k, v| k.intern == :reportable || k.intern == :pivot } )
|
59
|
+
|
60
|
+
if !params[:report_item][:reportable].blank?
|
61
|
+
id, model = params[:report_item][:reportable].split('-')
|
62
|
+
@report_item.reportable = model.constantize.find(id)
|
63
|
+
end
|
64
|
+
|
65
|
+
if !params[:report_item][:pivot].blank?
|
66
|
+
id, model = params[:report_item][:pivot].split('-')
|
67
|
+
@report_item.pivot = model.constantize.find(id)
|
68
|
+
end
|
69
|
+
|
70
|
+
if @report_item.save
|
71
|
+
render :json => { :success => true,
|
72
|
+
:close_dialog => true,
|
73
|
+
:result => "<span>Successfully updated report item</span>",
|
74
|
+
:also => [ { :item => ".report-report-items", :result => render_to_string( :partial => "mg/reports/report_report_items", :locals => { :report => @report_item.report }) } ] }
|
75
|
+
else
|
76
|
+
render :json => { :success => true,
|
77
|
+
:result => render_to_string(:action => :edit, :layout => 'xhr') }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
#TODO: Destroy
|
82
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
class Mg::ReportsController < Mg
|
2
|
+
# GET /mg_reports
|
3
|
+
# GET /mg_reports.xml
|
4
|
+
def index
|
5
|
+
@reports = Mg::Report.all
|
6
|
+
|
7
|
+
respond_to do |format|
|
8
|
+
format.html # index.html.erb
|
9
|
+
format.xml { render :xml => @reports }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /mg_reports/1
|
14
|
+
# GET /mg_reports/1.xml
|
15
|
+
def show
|
16
|
+
@report = Mg::Report.find(params[:id])
|
17
|
+
|
18
|
+
respond_to do |format|
|
19
|
+
format.html # show.html.erb
|
20
|
+
format.xml { render :xml => @report }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def show_svg
|
25
|
+
@report = Mg::Report.find(params[:id])
|
26
|
+
|
27
|
+
render :text => render_to_string(:partial => "mg/reports/report", :layout => '_pdf', :locals => { :report => @report } )
|
28
|
+
response.content_type = 'application/xhtml+xml'
|
29
|
+
end
|
30
|
+
|
31
|
+
# GET /mg_reports/new
|
32
|
+
# GET /mg_reports/new.xml
|
33
|
+
def new
|
34
|
+
@report = Mg::Report.new
|
35
|
+
|
36
|
+
respond_to do |format|
|
37
|
+
format.html # new.html.erb
|
38
|
+
format.xml { render :xml => @report }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# GET /mg_reports/1/edit
|
43
|
+
def edit
|
44
|
+
@report = Mg::Report.find(params[:id])
|
45
|
+
end
|
46
|
+
|
47
|
+
# POST /mg_reports
|
48
|
+
# POST /mg_reports.xml
|
49
|
+
def create
|
50
|
+
@report = Mg::Report.new(params[:report])
|
51
|
+
|
52
|
+
respond_to do |format|
|
53
|
+
if @report.save
|
54
|
+
format.html { flash[:notice] = 'Your report was successfully created, now add some report items.'; redirect_to(edit_mg_report_url @report) }
|
55
|
+
format.xml { render :xml => @report, :status => :created, :location => @report }
|
56
|
+
else
|
57
|
+
format.html { render :action => "new" }
|
58
|
+
format.xml { render :xml => @report.errors, :status => :unprocessable_entity }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# PUT /mg_reports/1
|
64
|
+
# PUT /mg_reports/1.xml
|
65
|
+
def update
|
66
|
+
@report = Mg::Report.find(params[:id])
|
67
|
+
|
68
|
+
respond_to do |format|
|
69
|
+
if @report.update_attributes(params[:report])
|
70
|
+
format.html { redirect_to(@report, :notice => 'Mg::Report was successfully updated.') }
|
71
|
+
format.xml { head :ok }
|
72
|
+
else
|
73
|
+
format.html { render :action => "edit" }
|
74
|
+
format.xml { render :xml => @report.errors, :status => :unprocessable_entity }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# DELETE /mg_reports/1
|
80
|
+
# DELETE /mg_reports/1.xml
|
81
|
+
def destroy
|
82
|
+
@report = Mg::Report.find(params[:id])
|
83
|
+
@report.destroy
|
84
|
+
|
85
|
+
respond_to do |format|
|
86
|
+
format.html { redirect_to(mg_reports_url) }
|
87
|
+
format.xml { head :ok }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
################
|
3
|
+
# Setup PDFKit #
|
4
|
+
################
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'pdfkit'
|
8
|
+
rescue LoadError
|
9
|
+
raise "Mountain Goat Reports will not work without the 'pdfkit' gem (please run `gem install pdfkit`)"
|
10
|
+
end
|
11
|
+
|
12
|
+
######################
|
13
|
+
# Setup svg-graph #
|
14
|
+
######################
|
15
|
+
|
16
|
+
begin
|
17
|
+
require 'SVG/Graph/TimeSeries'
|
18
|
+
rescue LoadError
|
19
|
+
raise "Mountain Goat Reports will not work without the 'svg-graph' gem (please run `gem install svg-graph`)"
|
20
|
+
end
|
21
|
+
|
22
|
+
############################
|
23
|
+
# TODO: Verify Email Setup #
|
24
|
+
############################
|
25
|
+
|
26
|
+
class MG
|
27
|
+
def self.deliver(delivery_set = nil)
|
28
|
+
mg_yml = YAML::load(File.open("#{RAILS_ROOT}/config/mountain-goat.yml"))
|
29
|
+
|
30
|
+
if mg_yml.blank? || mg_yml[RAILS_ENV].blank? || mg_yml[RAILS_ENV]['wkhtmltopdf'].blank?
|
31
|
+
raise "Please configure wkhtmltopdf settings in #{RAILS_ROOT}/config/mountain-goat.yml"
|
32
|
+
end
|
33
|
+
|
34
|
+
PDFKit.configure do |cz|
|
35
|
+
cz.wkhtmltopdf = mg_yml[RAILS_ENV]['wkhtmltopdf']
|
36
|
+
cz.default_options = { :'custom-header' => "'Content-Type' 'application/xhtml+xml'" }
|
37
|
+
end
|
38
|
+
|
39
|
+
if delivery_set.nil?
|
40
|
+
reports = Mg::Report.all
|
41
|
+
else
|
42
|
+
reports = Mg::Report.find(:all, :conditions => { :delivery_set => delivery_set.to_s } )
|
43
|
+
end
|
44
|
+
|
45
|
+
#We need to render the report report_show
|
46
|
+
reports.each do |report|
|
47
|
+
puts "Delivering report: #{report.title}"
|
48
|
+
av = ActionView::Base.new
|
49
|
+
av.view_paths = File.join([File.dirname(__FILE__), 'views/mountain_goat/'])
|
50
|
+
data = av.render(:partial => 'mg/reports/report', :layout => 'layouts/pdf', :locals => { :report => report } )
|
51
|
+
|
52
|
+
#Oddly, the file extension matters most here
|
53
|
+
tmp = Tempfile.new(['chart', '.xhtml'])
|
54
|
+
tmp << data
|
55
|
+
tmp.flush
|
56
|
+
|
57
|
+
kit = PDFKit.new(File.new(tmp.path), :page_size => 'Letter')
|
58
|
+
pdf = kit.to_pdf
|
59
|
+
tmp.close
|
60
|
+
|
61
|
+
Mg::ReportMailer.deliver_report(report, pdf)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -7,49 +7,165 @@ module MetricTracking
|
|
7
7
|
define_method :clear!, lambda {}
|
8
8
|
end
|
9
9
|
|
10
|
-
|
10
|
+
Mime::Type.register "application/xhtml+xml", :xhtml
|
11
|
+
|
11
12
|
ActionController::Routing::Routes.draw do |map|
|
12
|
-
map.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
13
|
+
map.namespace :mg do |mg|
|
14
|
+
mg.mg '/mg', :controller => :converts, :action => :index, :path_prefix => ""
|
15
|
+
mg.login '/login', :controller => :mountain_goat, :action => :login
|
16
|
+
mg.login_create '/login/create', :controller => :mountain_goat, :action => :login_create
|
17
|
+
mg.resources :metric_variants
|
18
|
+
mg.resources :converts, :has_many => [ :rallies ]
|
19
|
+
mg.resources :metrics, :has_many => :metric_variants
|
20
|
+
mg.resources :rallies, :collection => { :new_rallies => :get }
|
21
|
+
mg.resources :reports, :has_many => :report_items, :member => { :show_svg => :get }
|
22
|
+
mg.resources :report_items, :member => { :destroy => :get, :update => :post }, :collection => { :get_extra => :get }
|
23
|
+
mg.resources :playground, :collection => { :test => :get }
|
24
|
+
mg.new_rallies '/rallies/new', :controller => :rallies, :action => :new_rallies
|
25
|
+
mg.fresh_metrics '/fresh-metrics', :controller => :metrics, :action => :fresh_metrics
|
26
|
+
mg.connect '/public/:file', :controller => :mountain_goat, :action => :fetch
|
27
|
+
end
|
22
28
|
end
|
23
29
|
|
24
30
|
module Controller
|
25
31
|
|
32
|
+
#This is just for testing
|
33
|
+
def mg_rand
|
34
|
+
return "(SELECT #{@mg_i.nil? ? 1 : @mg_i.to_f})" if defined?(MOUNTAIN_GOAT_TEST) && MOUNTAIN_GOAT_TEST
|
35
|
+
"RAND()"
|
36
|
+
end
|
37
|
+
|
38
|
+
def mg_epsilon
|
39
|
+
if @mg_epsilon.nil?
|
40
|
+
@mg_epsilon = 0.1 #default
|
41
|
+
mg_yml = nil
|
42
|
+
begin
|
43
|
+
mg_yml = YAML::load(File.open("#{RAILS_ROOT}/config/mountain-goat.yml"))
|
44
|
+
rescue
|
45
|
+
end
|
46
|
+
if mg_yml
|
47
|
+
if mg_yml.has_key?(RAILS_ENV) && mg_yml[RAILS_ENV].has_key?('epsilon')
|
48
|
+
@mg_epsilon = mg_yml[RAILS_ENV]['epsilon'].to_f
|
49
|
+
elsif mg_yml.has_key?('settings') && mg_yml['settings'].has_key?('epsilon')
|
50
|
+
@mg_epsilon = mg_yml['settings']['epsilon'].to_f
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
return @mg_epsilon
|
55
|
+
end
|
56
|
+
|
57
|
+
def mg_strategy
|
58
|
+
if @mg_strategy.nil?
|
59
|
+
@mg_strategy = 'e-greedy' #default
|
60
|
+
mg_yml = nil
|
61
|
+
begin
|
62
|
+
mg_yml = YAML::load(File.open("#{RAILS_ROOT}/config/mountain-goat.yml"))
|
63
|
+
rescue
|
64
|
+
end
|
65
|
+
if mg_yml
|
66
|
+
if mg_yml.has_key?(RAILS_ENV) && mg_yml[RAILS_ENV].has_key?('strategy')
|
67
|
+
@mg_strategy = mg_yml[RAILS_ENV]['strategy']
|
68
|
+
elsif mg_yml.has_key?('settings') && mg_yml['settings'].has_key?('strategy')
|
69
|
+
@mg_strategy = mg_yml['settings']['strategy']
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
return @mg_strategy
|
74
|
+
end
|
75
|
+
|
76
|
+
def mg_apply_strategy(metric)
|
77
|
+
case mg_strategy.downcase
|
78
|
+
when 'e-greedy'
|
79
|
+
logger.warn Mg::MetricVariant.all(:order => "CASE WHEN served = 0 THEN 1 ELSE 0 END DESC, CASE WHEN #{mg_rand} < #{mg_epsilon.to_f} THEN #{mg_rand} ELSE CASE WHEN served = 0 THEN -1 ELSE reward / served END END DESC, #{mg_rand} DESC", :conditions => { :metric_id => metric.id } )
|
80
|
+
return Mg::MetricVariant.first(:order => "CASE WHEN served = 0 THEN 1 ELSE 0 END DESC, CASE WHEN #{mg_rand} < #{mg_epsilon.to_f} THEN #{mg_rand} ELSE CASE WHEN served = 0 THEN -1 ELSE reward / served END END DESC, #{mg_rand} DESC", :conditions => { :metric_id => metric.id } )
|
81
|
+
when 'e-greedy-decreasing'
|
82
|
+
return Mg::MetricVariant.first(:order => "CASE WHEN served = 0 THEN 1 ELSE 0 END DESC,
|
83
|
+
CASE WHEN #{mg_rand} < #{mg_epsilon.to_f} / ( select sum(served) from mg_metric_variants where metric_id = #{ metric.id.to_i } ) THEN #{mg_rand} ELSE CASE WHEN served = 0 THEN -1 ELSE reward / served END END DESC,
|
84
|
+
#{mg_rand} DESC", :conditions => { :metric_id => metric.id } ) # * log( ( select sum(served) from mg_metric_variants where metric_id = #{ metric.id.to_i } ) )
|
85
|
+
when 'a/b'
|
86
|
+
return Mg::MetricVariant.first(:order => "#{mg_rand} DESC", :conditions => { :metric_id => metric.id } )
|
87
|
+
else
|
88
|
+
raise "Invalid strategy #{mg_strategy}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def mg_storage
|
93
|
+
if @mg_storage.nil?
|
94
|
+
@mg_storage = defined?(cookies) ? cookies : nil
|
95
|
+
|
96
|
+
mg_yml = nil
|
97
|
+
begin
|
98
|
+
mg_yml = YAML::load(File.open("#{RAILS_ROOT}/config/mountain-goat.yml"))
|
99
|
+
rescue
|
100
|
+
end
|
101
|
+
if mg_yml
|
102
|
+
if mg_yml.has_key?(RAILS_ENV) && mg_yml[RAILS_ENV].has_key?('storage')
|
103
|
+
uc = mg_yml[RAILS_ENV]['storage'].strip
|
104
|
+
@mg_storage = ( uc == "cookies" && defined?(cookies) ) ? cookies : ( uc == "session" && defined?(session) ) ? session : nil
|
105
|
+
elsif mg_yml.has_key?('settings') && mg_yml['settings'].has_key?('storage')
|
106
|
+
uc = mg_yml['settings']['storage'].strip
|
107
|
+
@mg_storage = ( uc == "cookies" && defined?(cookies) ) ? cookies : ( uc == "session" && defined?(session) ) ? session : nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
@mg_storage = {} if @mg_storage.nil? #'none'
|
112
|
+
return @mg_storage
|
113
|
+
end
|
114
|
+
|
26
115
|
######################
|
27
116
|
# Metric Tracking #
|
28
117
|
######################
|
29
118
|
|
30
|
-
def
|
119
|
+
def bds(metric_type, &block)
|
31
120
|
raise ArgumentError, "Switch variant needs block" if !block_given?
|
32
|
-
metric
|
33
|
-
block.call(SwitchVariant.new( logger, metric,
|
121
|
+
metric = get_metric( metric_type, true )
|
122
|
+
block.call(SwitchVariant.new( logger, metric, nil ) )
|
34
123
|
|
35
|
-
var = get_switch_metric_variant(metric_type
|
36
|
-
block.call(SwitchVariant.new( logger, metric,
|
124
|
+
var = get_switch_metric_variant( metric_type )
|
125
|
+
block.call(SwitchVariant.new( logger, metric, var ) )
|
126
|
+
end
|
127
|
+
|
128
|
+
def bd(metric_type, default, opts = {}, opt = nil)
|
129
|
+
return get_metric_variant(metric_type, default, opts, opt)[:value]
|
130
|
+
end
|
131
|
+
|
132
|
+
def bdd(metric_type, default, opts = {}, opt = nil)
|
133
|
+
return get_metric_variant(metric_type, default, opts, opt)
|
134
|
+
end
|
135
|
+
|
136
|
+
#Legacy
|
137
|
+
def sv(metric_type, convert_type, &block)
|
138
|
+
bds(metric_type, &block)
|
37
139
|
end
|
38
140
|
|
39
141
|
def mv(metric_type, convert_type, default, opts = {}, opt = nil)
|
40
|
-
|
142
|
+
bd(metric_type, default, opts, opt)
|
41
143
|
end
|
42
144
|
|
43
145
|
def mv_detailed(metric_type, convert_type, default, opts = {}, opt = nil)
|
44
|
-
|
146
|
+
bdd(metric_type, default, opts, opt)
|
45
147
|
end
|
46
148
|
|
47
149
|
#shorthand
|
150
|
+
def rw(convert_type, reward, options = {})
|
151
|
+
self.bandit_reward(convert_type, reward, options)
|
152
|
+
end
|
153
|
+
|
48
154
|
def rc(convert_type, options = {})
|
49
|
-
self.
|
155
|
+
self.bandit_reward(convert_type, 1, options)
|
50
156
|
end
|
51
157
|
|
52
158
|
def record_conversion(convert_type, options = {})
|
159
|
+
self.bandit_reward(convert_type, 1, options)
|
160
|
+
end
|
161
|
+
|
162
|
+
#allows bandit_reward(convert, options)
|
163
|
+
def bandit_reward(convert_type, reward, options = {})
|
164
|
+
|
165
|
+
if reward.is_a?(Hash) #allow arguments bandit_reward(convert, options)
|
166
|
+
options = reward
|
167
|
+
reward = 0
|
168
|
+
end
|
53
169
|
|
54
170
|
metrics = {} #for user-defined metrics
|
55
171
|
options = options.with_indifferent_access
|
@@ -71,18 +187,18 @@ module MetricTracking
|
|
71
187
|
|
72
188
|
logger.warn "Recording conversion #{convert_type.to_s} with options #{options.inspect}"
|
73
189
|
|
74
|
-
convert = Convert.first( :conditions => { :convert_type => convert_type.to_s } )
|
190
|
+
convert = Mg::Convert.first( :conditions => { :convert_type => convert_type.to_s } )
|
75
191
|
|
76
192
|
#now, we just create the convert if we don't have one
|
77
|
-
convert = Convert.create!( :convert_type => convert_type.to_s, :name => convert_type.to_s ) if convert.nil?
|
78
|
-
|
193
|
+
convert = Mg::Convert.create!( :convert_type => convert_type.to_s, :name => convert_type.to_s, :reward => reward ) if convert.nil?
|
194
|
+
|
79
195
|
#first, let's tally for the conversion itself
|
80
196
|
#we need to see what meta information we should fill based on the conversion type
|
81
|
-
Rally.create!( { :convert_id => convert.id } ).set_meta_data(options)
|
197
|
+
Mg::Rally.create!( { :convert_id => convert.id } ).set_meta_data(options)
|
82
198
|
|
83
199
|
#User-defined metric tallies
|
84
200
|
metrics.each do |metric_type, variant_id|
|
85
|
-
m = Metric.find_by_metric_type(metric_type)
|
201
|
+
m = Mg::Metric.find_by_metric_type(metric_type)
|
86
202
|
if m.nil?
|
87
203
|
logger.warn "Missing user-defined metric #{metric_type}"
|
88
204
|
next
|
@@ -96,27 +212,27 @@ module MetricTracking
|
|
96
212
|
end
|
97
213
|
|
98
214
|
logger.warn "Tallying conversion #{convert.name} for #{m.title} - #{v.name} (#{v.value} - #{v.id})"
|
99
|
-
v.tally_convert
|
215
|
+
v.tally_convert(convert, reward)
|
100
216
|
end
|
101
217
|
|
102
|
-
if
|
103
|
-
#we just converted, let's tally each of our metrics (from cookies)
|
104
|
-
|
218
|
+
if !mg_storage.nil?
|
219
|
+
#we just converted, let's tally each of our metrics (from cookies or session)
|
220
|
+
Mg::Metric.all.each do |metric|
|
105
221
|
metric_sym = "metric_#{metric.metric_type}".to_sym
|
106
222
|
metric_variant_sym = "metric_#{metric.metric_type}_variant".to_sym
|
107
223
|
|
108
|
-
value =
|
109
|
-
variant_id =
|
224
|
+
value = mg_storage[metric_sym]
|
225
|
+
variant_id = mg_storage[metric_variant_sym]
|
110
226
|
|
111
227
|
#logger.warn "Value: #{metric_sym} - #{value}"
|
112
228
|
#logger.warn "Value: #{metric_variant_sym} - #{variant_id}"
|
113
229
|
|
114
230
|
if variant_id.blank? #the user just doesn't have this set
|
115
|
-
|
231
|
+
#This is now common-case
|
116
232
|
next
|
117
233
|
end
|
118
234
|
|
119
|
-
variant = MetricVariant.first(:conditions => { :id => variant_id.to_i } )
|
235
|
+
variant = Mg::MetricVariant.first(:conditions => { :id => variant_id.to_i } )
|
120
236
|
|
121
237
|
if variant.nil?
|
122
238
|
logger.error "Variant #{variant_id} not in metric variants for #{metric.title}"
|
@@ -128,7 +244,7 @@ module MetricTracking
|
|
128
244
|
end
|
129
245
|
|
130
246
|
logger.warn "Tallying conversion #{convert.name} for #{metric.title} - #{variant.name} (#{variant.value} - #{variant.id})"
|
131
|
-
variant.tally_convert
|
247
|
+
variant.tally_convert(convert, reward)
|
132
248
|
end
|
133
249
|
end
|
134
250
|
end
|
@@ -136,15 +252,15 @@ module MetricTracking
|
|
136
252
|
private
|
137
253
|
|
138
254
|
#returns a map { :value => value, :variant_id => id }
|
139
|
-
def get_metric_variant(metric_type,
|
255
|
+
def get_metric_variant(metric_type, default, opts = {}, opt = nil)
|
140
256
|
metric_sym = "metric_#{metric_type}#{ opt.nil? ? "" : '_' + opt.to_s }".to_sym
|
141
257
|
metric_variant_sym = "metric_#{metric_type}_variant".to_sym
|
142
258
|
|
143
259
|
#first, we'll check for a cookie value
|
144
|
-
if
|
260
|
+
if !mg_storage.nil? && mg_storage[metric_sym] && !mg_storage[metric_sym].blank?
|
145
261
|
#we have the cookie
|
146
|
-
variant_id =
|
147
|
-
variant = MetricVariant.first(:conditions => { :id => variant_id.to_i } )
|
262
|
+
variant_id = mg_storage[metric_variant_sym]
|
263
|
+
variant = Mg::MetricVariant.first(:conditions => { :id => variant_id.to_i } )
|
148
264
|
if !variant.nil?
|
149
265
|
if variant.metric.tally_each_serve
|
150
266
|
variant.tally_serve
|
@@ -153,46 +269,44 @@ module MetricTracking
|
|
153
269
|
logger.warn "Serving metric #{metric_type} #{ opt.nil? ? "" : opt.to_s } without finding / tallying variant."
|
154
270
|
end
|
155
271
|
|
156
|
-
return { :value =>
|
272
|
+
return { :value => mg_storage[metric_sym], :variant_id => mg_storage[metric_variant_sym] } #it's the best we can do
|
157
273
|
else
|
158
274
|
#we don't have the cookie, let's find a value to set
|
159
|
-
metric
|
275
|
+
metric = get_metric( metric_type, false )
|
160
276
|
|
161
|
-
|
162
|
-
sum_priority = MetricVariant.first(:select => "SUM(priority) as sum_priority", :conditions => { :metric_id => metric.id } ).sum_priority.to_f
|
163
|
-
|
164
|
-
if sum_priority > 0.0
|
165
|
-
metric_variant = MetricVariant.first(:order => "RAND() * ( priority / #{sum_priority.to_f} ) DESC", :conditions => { :metric_id => metric.id } )
|
166
|
-
end
|
277
|
+
metric_variant = mg_apply_strategy(metric)
|
167
278
|
|
168
279
|
if metric_variant.nil?
|
169
280
|
logger.warn "Missing metric variants for #{metric_type}"
|
170
|
-
metric_variant = MetricVariant.create!( { :metric_id => metric.id, :value => default, :name => default }.merge(opts) )
|
281
|
+
metric_variant = Mg::MetricVariant.create!( { :metric_id => metric.id, :value => default, :name => default }.merge(opts) )
|
282
|
+
end
|
283
|
+
|
284
|
+
if metric_variant.metric.tally_each_serve
|
285
|
+
metric_variant.tally_serve #donate we served this to a user
|
171
286
|
end
|
172
287
|
|
173
|
-
metric_variant.tally_serve #donate we served this to a user
|
174
288
|
value = metric_variant.read_attribute( opt.nil? ? :value : opt )
|
175
289
|
logger.debug "Serving #{metric_variant.name} (#{value}) for #{metric_sym}"
|
176
290
|
#good, we have a variant, let's store it in session
|
177
291
|
|
178
|
-
if
|
179
|
-
|
180
|
-
|
292
|
+
if !mg_storage.nil?
|
293
|
+
mg_storage[metric_sym] = value #, :domain => WILD_DOMAIN
|
294
|
+
mg_storage[metric_variant_sym] = metric_variant.id #, :domain => WILD_DOMAIN
|
181
295
|
end
|
182
296
|
|
183
297
|
return { :value => value, :variant_id => metric_variant.id }
|
184
298
|
end
|
185
299
|
end
|
186
300
|
|
187
|
-
def get_switch_metric_variant(metric_type
|
301
|
+
def get_switch_metric_variant(metric_type)
|
188
302
|
metric_variant_sym = "metric_#{metric_type}_variant".to_sym
|
189
303
|
|
190
304
|
#first, we'll check for a cookie selection
|
191
|
-
if
|
305
|
+
if !mg_storage.nil? && mg_storage[metric_variant_sym] && !mg_storage[metric_variant_sym].blank?
|
192
306
|
#we have the cookie
|
193
307
|
|
194
|
-
variant_id =
|
195
|
-
variant = MetricVariant.first(:conditions => { :id => variant_id.to_i } )
|
308
|
+
variant_id = mg_storage[metric_variant_sym]
|
309
|
+
variant = Mg::MetricVariant.first(:conditions => { :id => variant_id.to_i } )
|
196
310
|
if !variant.nil?
|
197
311
|
|
198
312
|
if variant.metric.tally_each_serve
|
@@ -208,46 +322,38 @@ module MetricTracking
|
|
208
322
|
end
|
209
323
|
|
210
324
|
#we don't have the cookie, let's find a value to set
|
211
|
-
metric
|
325
|
+
metric = get_metric( metric_type, true )
|
212
326
|
|
213
|
-
|
214
|
-
sum_priority = MetricVariant.first(:select => "SUM(priority) as sum_priority", :conditions => { :metric_id => metric.id } ).sum_priority.to_f
|
215
|
-
|
216
|
-
if sum_priority > 0.0
|
217
|
-
metric_variant = MetricVariant.first(:order => "RAND() * ( priority / #{sum_priority.to_f} ) DESC", :conditions => { :metric_id => metric.id } )
|
218
|
-
end
|
327
|
+
metric_variant = mg_apply_strategy(metric)
|
219
328
|
|
220
329
|
if metric_variant.nil?
|
221
330
|
logger.warn "Missing metric variants for #{metric_type}"
|
222
331
|
raise ArgumentError, "Missing variants for switch-type #{metric_type}"
|
223
332
|
end
|
224
333
|
|
225
|
-
metric_variant.
|
334
|
+
if metric_variant.metric.tally_each_serve
|
335
|
+
metric_variant.tally_serve #donate we served this to a user
|
336
|
+
end
|
337
|
+
|
226
338
|
logger.debug "Serving #{metric_variant.name} (#{metric_variant.switch_type}) for #{metric.title} (switch-type)"
|
227
339
|
#good, we have a variant, let's store it in session (not the value, just the selection)
|
228
|
-
if
|
229
|
-
|
340
|
+
if !mg_storage.nil?
|
341
|
+
mg_storage[metric_variant_sym] = metric_variant.id #, :domain => WILD_DOMAIN
|
230
342
|
end
|
231
343
|
|
232
344
|
return metric_variant
|
233
345
|
end
|
234
346
|
|
235
|
-
def
|
347
|
+
def get_metric(metric_type, is_switch = false)
|
236
348
|
|
237
|
-
metric = Metric.first(:conditions => { :metric_type => metric_type.to_s } )
|
349
|
+
metric = Mg::Metric.first(:conditions => { :metric_type => metric_type.to_s } )
|
238
350
|
|
239
|
-
conv = Convert.find_by_convert_type( convert_type.to_s )
|
240
|
-
if conv.nil?
|
241
|
-
logger.warn "Missing convert type #{convert_type.to_s} -- creating"
|
242
|
-
conv = Convert.create( :convert_type => convert_type.to_s, :name => convert_type.to_s ) if conv.nil?
|
243
|
-
end
|
244
|
-
|
245
351
|
if metric.nil? #we don't have a metric of this type
|
246
352
|
logger.warn "Missing metric type #{metric_type.to_s} -- creating"
|
247
|
-
metric = Metric.create( :metric_type => metric_type.to_s, :title => metric_type.to_s, :
|
353
|
+
metric = Mg::Metric.create( :metric_type => metric_type.to_s, :title => metric_type.to_s, :is_switch => is_switch )
|
248
354
|
end
|
249
355
|
|
250
|
-
return metric
|
356
|
+
return metric
|
251
357
|
end
|
252
358
|
end
|
253
359
|
|
@@ -263,6 +369,18 @@ module MetricTracking
|
|
263
369
|
def sv(*args, &block)
|
264
370
|
@controller.send(:sv, *args, &block)
|
265
371
|
end
|
372
|
+
|
373
|
+
def bd(*args, &block)
|
374
|
+
@controller.send(:bd, *args, &block)
|
375
|
+
end
|
376
|
+
|
377
|
+
def bdd(*args, &block)
|
378
|
+
@controller.send(:bdd, *args, &block)
|
379
|
+
end
|
380
|
+
|
381
|
+
def bds(*args, &block)
|
382
|
+
@controller.send(:bds, *args, &block)
|
383
|
+
end
|
266
384
|
end
|
267
385
|
end
|
268
386
|
|