diff --git a/Gemfile b/Gemfile index 174be1d5..44388fc3 100644 --- a/Gemfile +++ b/Gemfile @@ -39,6 +39,7 @@ gem "oauth" # for twitter-posting bot gem "mail" # for parsing incoming mail gem "ruumba" # tests views gem "sitemap_generator" # for better search engine indexing +gem "svg-graph", require: 'SVG/Graph/TimeSeries' # for charting, note workaround in lib/time_series.rb gem 'transaction_retry' # mitigate https://github.com/lobsters/lobsters-ansible/issues/39 group :test, :development do diff --git a/Gemfile.lock b/Gemfile.lock index 7a892fea..6ff2c559 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -231,6 +231,7 @@ GEM actionpack (>= 3.0) activesupport (>= 3.0) sprockets (>= 2.8, < 4.0) + svg-graph (2.2.0) thor (1.0.1) thread_safe (0.3.6) transaction_isolation (1.0.5) @@ -296,6 +297,7 @@ DEPENDENCIES scenic-mysql_adapter sitemap_generator sprockets-rails (= 2.3.3) + svg-graph transaction_retry uglifier (>= 1.3.0) vcr diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb new file mode 100644 index 00000000..a2247207 --- /dev/null +++ b/app/controllers/stats_controller.rb @@ -0,0 +1,77 @@ +class StatsController < ApplicationController + FIRST_MONTH = Time.new(2012, 7, 3).utc.freeze + TIMESCALE_DIVISIONS = "1 year".freeze + + def index + @title = "Stats" + + @users_graph = monthly_graph("users_graph", { + :graph_title => "Users joining by month", + :scale_y_divisions => 50, + }) { + User.group("date_format(created_at, '%Y-%m')") + } + + @stories_graph = monthly_graph("stories_graph", { + :graph_title => "Stories submitted by month", + :scale_y_divisions => 100, + }) { + Story.group("date_format(created_at, '%Y-%m')") + } + + @comments_graph = monthly_graph("comments_graph", { + :graph_title => "Comments posted by month", + :scale_y_divisions => 1_000, + }) { + Comment.group("date_format(created_at, '%Y-%m')") + } + + @votes_graph = monthly_graph("votes_graph", { + :graph_title => "Votes cast by month", + :scale_y_divisions => 10_000, + }) { + Vote.group("date_format(updated_at, '%Y-%m')") + } + end + +private + + def monthly_graph(cache_key, opts) + Rails.cache.fetch(cache_key, expires_in: 1.day) { + defaults = { + :width => 800, + :height => 300, + :graph_title => "Graph", + :show_graph_title => false, + :no_css => false, + :key => false, + :scale_x_integers => true, + :scale_y_integers => false, + :show_data_values => false, + :show_x_guidelines => false, + :show_x_title => false, + :x_title => "Time", + :show_y_title => false, + :y_title => "Users", + :y_title_text_direction => :bt, + :stagger_x_labels => false, + :x_label_format => "%Y-%m", + :y_label_format => "%Y-%m", + :min_x_value => FIRST_MONTH, + :timescale_divisions => TIMESCALE_DIVISIONS, + :add_popups => true, + :popup_format => "%Y-%m", + :area_fill => false, + :min_y_value => 0, + :number_format => "%d", + :show_lines => false, + } + graph = TimeSeries.new(defaults.merge(opts)) + graph.add_data( + data: yield.count.to_a.flatten, + template: "%Y-%m", + ) + graph.burn_svg_only + } + end +end diff --git a/app/views/home/about.html.erb b/app/views/home/about.html.erb index 8676c00c..b0a02091 100644 --- a/app/views/home/about.html.erb +++ b/app/views/home/about.html.erb @@ -148,7 +148,8 @@
The Lobsters community is in a sweet spot that it's large enough to be worth asking questions about and small enough the answers make sense. - If you're curious about stats, Peter is happy to run queries against the database and Rails/MySQL/nginx logs (but not write them for you), + We have some basic stats available, + and Peter is happy to run queries against the database and Rails/MySQL/nginx logs (but not write them for you), as long as they don't reveal personal info like IPs, browsing, and voting or create “worst-of” leaderboards celebrating most-downvoted users/comments/stories. If you're an academic researcher, please be like MIT, not like UChicago secretly experimenting on maintainers without IRB review.
diff --git a/app/views/stats/index.html.erb b/app/views/stats/index.html.erb new file mode 100644 index 00000000..07e73a19 --- /dev/null +++ b/app/views/stats/index.html.erb @@ -0,0 +1,28 @@ ++Want more info? +Write a query. +
+ + + +