diff --git a/app/assets/javascripts/stats.js.coffee b/app/assets/javascripts/stats.js.coffee new file mode 100644 index 000000000..7fcdfb00a --- /dev/null +++ b/app/assets/javascripts/stats.js.coffee @@ -0,0 +1,11 @@ +# Helper for generate C3.js graphs +#---------------------------------------------------------------------- + +buildGraph = (el) -> + url = $(el).data 'graph' + conf = bindto: el, data: {x: 'x', url: url, mimeType: 'json'}, axis: { x: {type: 'timeseries',tick: { format: '%Y-%m-%d' } }} + graph = c3.generate conf + +App.Stats = + initialize: -> + buildGraph(g) for g in $("[data-graph]") diff --git a/app/controllers/api/stats_controller.rb b/app/controllers/api/stats_controller.rb index 26fb373fb..d44262b45 100644 --- a/app/controllers/api/stats_controller.rb +++ b/app/controllers/api/stats_controller.rb @@ -1,10 +1,22 @@ class Api::StatsController < Api::ApiController def show - event_type = params[:event] - unless event_type.present? + unless params[:events].present? || params[:visits].present? return render json: {}, status: :bad_request end - render json: Ahoy::Event.where(name: event_type).group_by_day(:time).count + ds = Ahoy::DataSource.new + + if params[:events].present? + event_types = params[:events].split ',' + event_types.each do |event| + ds.add event.titleize, Ahoy::Event.where(name: event).group_by_day(:time).count + end + end + + if params[:visits].present? + ds.add "Visits", Visit.group_by_day(:started_at).count + end + + render json: ds.build end end diff --git a/app/helpers/stats_helper.rb b/app/helpers/stats_helper.rb new file mode 100644 index 000000000..e517767e3 --- /dev/null +++ b/app/helpers/stats_helper.rb @@ -0,0 +1,16 @@ +module StatsHelper + def events_chart_tag(events, opt={}) + events = events.join(',') if events.is_a? Array + opt[:data] ||= {} + opt[:data][:graph] = api_stats_path(events: events) + content_tag :div, "", opt + end + + def visits_chart_tag(opt={}) + events = events.join(',') if events.is_a? Array + opt[:data] ||= {} + opt[:data][:graph] = api_stats_path(visits: true) + content_tag :div, "", opt + end + +end diff --git a/app/views/stats/show.html.erb b/app/views/stats/show.html.erb index 0671b15ad..033d2714d 100644 --- a/app/views/stats/show.html.erb +++ b/app/views/stats/show.html.erb @@ -1,9 +1,13 @@

Stats

Visits

-<%= line_chart Visit.group_by_day(:started_at).count %> +<%= visits_chart_tag id: "visits" %> + +

Combined

+<%= events_chart_tag @event_types, id: 'combined' %> + <% @event_types.each do |event_type| %>

<%= event_type.titleize %>

- <%= line_chart api_stats_path(event: event_type) %> + <%= events_chart_tag event_type %> <% end %> diff --git a/spec/controllers/api/stats_controller_spec.rb b/spec/controllers/api/stats_controller_spec.rb index e2f4cd02b..9fd3ebd47 100644 --- a/spec/controllers/api/stats_controller_spec.rb +++ b/spec/controllers/api/stats_controller_spec.rb @@ -8,36 +8,89 @@ describe Api::StatsController do describe 'GET index' do let(:user) { create :user } - context 'event not present' do + context 'events or visits not present' do it 'should respond with bad_request' do sign_in user get :show + expect(response).to_not be_ok expect(response.status).to eq 400 end end - context 'event present' do - it 'should return event counts' do - time_1 = DateTime.yesterday.to_datetime - time_2 = DateTime.now + context 'events present' do + before :each do + time_1 = DateTime.parse("2015-01-01") + time_2 = DateTime.parse("2015-01-02") + time_3 = DateTime.parse("2015-01-03") - event_1 = create :ahoy_event, name: 'foo', time: time_1 - event_2 = create :ahoy_event, name: 'foo', time: time_1 - event_3 = create :ahoy_event, name: 'foo', time: time_2 - event_4 = create :ahoy_event, name: 'bar' + create :ahoy_event, name: 'foo', time: time_1 + create :ahoy_event, name: 'foo', time: time_1 + create :ahoy_event, name: 'foo', time: time_2 + create :ahoy_event, name: 'bar', time: time_1 + create :ahoy_event, name: 'bar', time: time_3 + create :ahoy_event, name: 'bar', time: time_3 + end + it 'should return single events formated for working with c3.js' do sign_in user - get :show, event: 'foo' + get :show, events: 'foo' expect(response).to be_ok data = JSON.parse(response.body) - dates = data.keys + expect(data).to eq "x"=>["2015-01-01", "2015-01-02"], "Foo"=>[2, 1] + end - expect(DateTime.parse dates.first).to eq time_1.utc.beginning_of_day - expect(DateTime.parse dates.last).to eq time_2.utc.beginning_of_day - expect(data[dates.first]).to eq 2 - expect(data[dates.last]).to eq 1 + it 'should return combined comma separated events formated for working with c3.js' do + sign_in user + get :show, events: 'foo,bar' + + expect(response).to be_ok + + data = JSON.parse(response.body) + expect(data).to eq "x"=>["2015-01-01", "2015-01-02", "2015-01-03"], "Foo"=>[2, 1, 0], "Bar"=>[1, 0, 2] + end + end + + context 'visits present' do + it 'should return visits formated for working with c3.js' do + time_1 = DateTime.parse("2015-01-01") + time_2 = DateTime.parse("2015-01-02") + + create :visit, started_at: time_1 + create :visit, started_at: time_1 + create :visit, started_at: time_2 + + sign_in user + get :show, visits: true + + expect(response).to be_ok + + data = JSON.parse(response.body) + expect(data).to eq "x"=>["2015-01-01", "2015-01-02"], "Visits"=>[2, 1] + end + end + + context 'visits and events present' do + it 'should return combined events and visits formated for working with c3.js' do + time_1 = DateTime.parse("2015-01-01") + time_2 = DateTime.parse("2015-01-02") + + create :ahoy_event, name: 'foo', time: time_1 + create :ahoy_event, name: 'foo', time: time_2 + create :ahoy_event, name: 'foo', time: time_2 + + create :visit, started_at: time_1 + create :visit, started_at: time_1 + create :visit, started_at: time_2 + + sign_in user + get :show, events: 'foo', visits: true + + expect(response).to be_ok + + data = JSON.parse(response.body) + expect(data).to eq "x"=>["2015-01-01", "2015-01-02"], "Foo"=>[1, 2], "Visits"=>[2, 1] end end end diff --git a/spec/factories.rb b/spec/factories.rb index 18b65b7f3..cf653a7cf 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -36,4 +36,9 @@ FactoryGirl.define do time DateTime.now sequence(:name) {|n| "Event #{n} type"} end + + factory :visit do + id { SecureRandom.uuid } + started_at DateTime.now + end end