diff --git a/Gemfile b/Gemfile index 0cec73e8a..e5d12b076 100644 --- a/Gemfile +++ b/Gemfile @@ -38,6 +38,7 @@ gem 'diff-lcs', :require => "diff/lcs/array" gem 'bcrypt-ruby', :require => "bcrypt" gem 'aws-s3', :require => "aws/s3" gem 'awesome_print' +gem 'statistics2' group :production do gem 'unicorn', :platforms => :ruby diff --git a/Gemfile.lock b/Gemfile.lock index 4251a77e0..8bb1a6f2d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -179,6 +179,7 @@ GEM multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) + statistics2 (0.54) term-ansicolor (1.1.4) therubyracer (0.11.4) libv8 (~> 3.11.8.12) @@ -241,6 +242,7 @@ DEPENDENCIES shoulda simple_form simplecov + statistics2 term-ansicolor therubyracer timecop diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb new file mode 100644 index 000000000..571332e66 --- /dev/null +++ b/app/controllers/reports_controller.rb @@ -0,0 +1,7 @@ +class ReportsController < ApplicationController + before_filter :janitor_only + + def user_promotions + @report = Reports::UserPromotions.new + end +end diff --git a/app/logical/reports/user_promotions.rb b/app/logical/reports/user_promotions.rb new file mode 100644 index 000000000..1ce13e8f1 --- /dev/null +++ b/app/logical/reports/user_promotions.rb @@ -0,0 +1,29 @@ +require 'statistics2' + +module Reports + class UserPromotions + def self.confidence_interval_for(user, n) + up_votes = Post.where("created_at >= ?", min_time).where(:uploader_id => user.id).where("fav_count >= ?", n).count + total_votes = Post.where("created_at >= ?", min_time).where(:uploader_id => user.id).count + ci_lower_bound(up_votes, total_votes, 0.95) + end + + def self.ci_lower_bound(pos, n, confidence) + if n == 0 + return 0 + end + + z = Statistics2.pnormaldist(1-(1-confidence)/2) + phat = 1.0*pos/n + 100 * (phat + z*z/(2*n) - z * Math.sqrt((phat*(1-phat)+z*z/(4*n))/n))/(1+z*z/n) + end + + def self.min_time + 30.days.ago + end + + def users + User.joins(:posts).where("users.level < ?", User::Levels::CONTRIBUTOR).where("posts.created_at >= ? and posts.fav_count >= 1", self.class.min_time).order("users.name") + end + end +end diff --git a/app/views/reports/user_promotions.html.erb b/app/views/reports/user_promotions.html.erb new file mode 100644 index 000000000..ae0364aeb --- /dev/null +++ b/app/views/reports/user_promotions.html.erb @@ -0,0 +1,30 @@ +
+
+

User Promotion Confidence Intervals

+ +

Binomial proportion confidence interval for how likely a user's uploads will achieve a fav count of at at least n with 95% confidence within the past 30 days.

+ + + + + + + + + + + + + <% @report.users.each do |user| %> + + + + + + + + <% end %> + +
UserLevelscore:1+score:5+score:10+
<%= link_to user.name, user_path(user) %><%= user.level_string %><%= number_to_percentage Reports::UserPromotions.confidence_interval_for(user, 1), :precision => 0 %><%= number_to_percentage Reports::UserPromotions.confidence_interval_for(user, 5), :precision => 0 %><%= number_to_percentage Reports::UserPromotions.confidence_interval_for(user, 10), :precision => 0 %>
+
+
\ No newline at end of file diff --git a/app/views/static/site_map.html.erb b/app/views/static/site_map.html.erb index b5ab87bbb..626befd5c 100644 --- a/app/views/static/site_map.html.erb +++ b/app/views/static/site_map.html.erb @@ -55,6 +55,12 @@
  • <%= link_to("Listing", pools_path) %>
  • <%= link_to("Changes", pool_versions_path) %>
  • + <% if CurrentUser.user.is_janitor? %> + + <% end %>