[Git][noosfero/noosfero][master] analytics: measure time on page

Bráulio Bhavamitra gitlab at gitlab.com
Fri Aug 28 20:47:20 BRT 2015


Bráulio Bhavamitra pushed to branch master at Noosfero / noosfero


Commits:
492c3d63 by Braulio Bhavamitra at 2015-08-28T20:17:16Z
analytics: measure time on page

- - - - -


12 changed files:

- + plugins/analytics/controllers/myprofile/analytics_plugin/stats_controller.rb
- plugins/analytics/lib/analytics_plugin.rb
- plugins/analytics/lib/analytics_plugin/base.rb
- plugins/analytics/lib/ext/profile.rb
- plugins/analytics/locales/en.yml
- plugins/analytics/locales/pt.yml
- plugins/analytics/models/analytics_plugin/page_view.rb
- plugins/analytics/models/analytics_plugin/visit.rb
- plugins/analytics/test/functional/content_viewer_controller_test.rb
- plugins/analytics/views/analytics_plugin/_body_ending.html.slim
- + plugins/analytics/views/analytics_plugin/stats/_table.html.slim
- + plugins/analytics/views/analytics_plugin/stats/index.html.slim


Changes:

=====================================
plugins/analytics/controllers/myprofile/analytics_plugin/stats_controller.rb
=====================================
--- /dev/null
+++ b/plugins/analytics/controllers/myprofile/analytics_plugin/stats_controller.rb
@@ -0,0 +1,21 @@
+class AnalyticsPlugin::StatsController < MyProfileController
+
+  no_design_blocks
+
+  before_filter :skip_page_view
+
+  def index
+  end
+
+  protected
+
+  def default_url_options
+    # avoid rails' use_relative_controller!
+    {use_route: '/'}
+  end
+
+  def skip_page_view
+    @analytics_skip_page_view = true
+  end
+
+end


=====================================
plugins/analytics/lib/analytics_plugin.rb
=====================================
--- a/plugins/analytics/lib/analytics_plugin.rb
+++ b/plugins/analytics/lib/analytics_plugin.rb
@@ -1,6 +1,7 @@
 module AnalyticsPlugin
 
-  TimeOnPageUpdateInterval = 2.minutes * 1000
+  TimeOnPageUpdateInterval = 2.minutes
+  TimeOnPageUpdateIntervalMs = TimeOnPageUpdateInterval * 1000
 
   extend Noosfero::Plugin::ParentMethods
 


=====================================
plugins/analytics/lib/analytics_plugin/base.rb
=====================================
--- a/plugins/analytics/lib/analytics_plugin/base.rb
+++ b/plugins/analytics/lib/analytics_plugin/base.rb
@@ -28,8 +28,7 @@ class AnalyticsPlugin::Base < Noosfero::Plugin
 
           unless profile.analytics_anonymous?
             # FIXME: use session.id in Rails 4
-            session_id = Marshal.load(Base64.decode64 request['_session_id'])['session_id'] rescue nil
-            #session_id = request.session_options[:id]
+            session_id = request.session_options[:id]
             page_view.user = user
             page_view.session_id = session_id
           end
@@ -40,4 +39,12 @@ class AnalyticsPlugin::Base < Noosfero::Plugin
     }]
   end
 
+  def control_panel_buttons
+    {
+      title: I18n.t('analytics_plugin.lib.plugin.panel_button'),
+      icon: 'analytics-access',
+      url: {controller: 'analytics_plugin/stats', action: :index}
+    }
+  end
+
 end


=====================================
plugins/analytics/lib/ext/profile.rb
=====================================
--- a/plugins/analytics/lib/ext/profile.rb
+++ b/plugins/analytics/lib/ext/profile.rb
@@ -13,7 +13,7 @@ end
 class Profile
 
   def analytics_settings attrs = {}
-    @analytics_settings ||= Noosfero::Plugin::Settings.new self, AnalyticsPlugin, attrs
+    @analytics_settings ||= Noosfero::Plugin::Settings.new self, ::AnalyticsPlugin, attrs
     attrs.each{ |a, v| @analytics_settings.send "#{a}=", v }
     @analytics_settings
   end


=====================================
plugins/analytics/locales/en.yml
=====================================
--- a/plugins/analytics/locales/en.yml
+++ b/plugins/analytics/locales/en.yml
@@ -5,6 +5,13 @@ en: &en
       plugin:
         name: 'Access tracking'
         description: 'Register the access of selected profiles'
+        panel_button: 'Access tracking'
+
+    views:
+      stats:
+        user: 'User'
+        initial_time: 'Time'
+        pages: 'Pages'
 
 en-US:
   <<: *en


=====================================
plugins/analytics/locales/pt.yml
=====================================
--- a/plugins/analytics/locales/pt.yml
+++ b/plugins/analytics/locales/pt.yml
@@ -5,6 +5,13 @@ pt: &pt
       plugin:
         name: 'Rastreio de accesso'
         description: 'Registra o acesso de perfis selecionados'
+        panel_button: 'Rastreio de accesso'
+
+    views:
+      stats:
+        user: 'Usuário'
+        initial_time: 'Horário'
+        pages: 'Páginas'
 
 pt-BR:
   <<: *pt


=====================================
plugins/analytics/models/analytics_plugin/page_view.rb
=====================================
--- a/plugins/analytics/models/analytics_plugin/page_view.rb
+++ b/plugins/analytics/models/analytics_plugin/page_view.rb
@@ -25,10 +25,24 @@ class AnalyticsPlugin::PageView < ActiveRecord::Base
   before_validation :fill_referer_page_view, on: :create
   before_validation :fill_visit, on: :create
 
+  scope :latest, -> { order 'request_started_at DESC' }
+
   def request_duration
     self.request_finished_at - self.request_started_at
   end
 
+  def initial_time
+    self.page_loaded_at || self.request_finished_at
+  end
+
+  def user_last_time_seen
+    self.initial_time + self.time_on_page
+  end
+
+  def user_on_page?
+    Time.now < self.user_last_time_seen + AnalyticsPlugin::TimeOnPageUpdateInterval
+  end
+
   def page_load!
     self.page_loaded_at = Time.now
     self.update_column :page_loaded_at, self.page_loaded_at
@@ -36,10 +50,9 @@ class AnalyticsPlugin::PageView < ActiveRecord::Base
 
   def increase_time_on_page!
     now = Time.now
-    initial_time = self.page_loaded_at || self.request_finished_at
-    return unless now > initial_time
+    return unless now > self.initial_time
 
-    self.time_on_page = now - initial_time
+    self.time_on_page = now - self.initial_time
     self.update_column :time_on_page, self.time_on_page
   end
 
@@ -59,7 +72,7 @@ class AnalyticsPlugin::PageView < ActiveRecord::Base
   end
 
   def fill_visit
-    self.visit = self.referer_page_view.visit if self.referer_page_view
+    self.visit = self.referer_page_view.visit if self.referer_page_view and self.referer_page_view.user_on_page?
     self.visit ||= AnalyticsPlugin::Visit.new profile: profile
   end
 


=====================================
plugins/analytics/models/analytics_plugin/visit.rb
=====================================
--- a/plugins/analytics/models/analytics_plugin/visit.rb
+++ b/plugins/analytics/models/analytics_plugin/visit.rb
@@ -3,9 +3,17 @@ class AnalyticsPlugin::Visit < ActiveRecord::Base
   attr_accessible *self.column_names
   attr_accessible :profile
 
-  default_scope -> { includes :page_views }
-
   belongs_to :profile
   has_many :page_views, class_name: 'AnalyticsPlugin::PageView', dependent: :destroy
 
+  default_scope -> { joins(:page_views).includes :page_views }
+
+  scope :latest, -> { order 'analytics_plugin_page_views.request_started_at DESC' }
+
+  def first_page_view
+    self.page_views.first
+  end
+
+  delegate :user, :initial_time, to: :first_page_view
+
 end


=====================================
plugins/analytics/test/functional/content_viewer_controller_test.rb
=====================================
--- a/plugins/analytics/test/functional/content_viewer_controller_test.rb
+++ b/plugins/analytics/test/functional/content_viewer_controller_test.rb
@@ -31,6 +31,8 @@ class ContentViewerControllerTest < ActionController::TestCase
 
     first_page_view = @community.page_views.order(:id).first
     assert_equal @request.referer, first_page_view.referer_url
+    assert_equal @user, first_page_view.user
+    assert first_page_view.request_duration > 0 and first_page_view.request_duration < 1
 
     @request.env['HTTP_REFERER'] = first_url
     get :view_page, profile: @community.identifier, page: @community.articles.last.path.split('/')
@@ -40,9 +42,13 @@ class ContentViewerControllerTest < ActionController::TestCase
     second_page_view = @community.page_views.order(:id).last
     assert_equal first_page_view, second_page_view.referer_page_view
 
-    assert_equal @user, second_page_view.user
-
-    assert second_page_view.request_duration > 0 and second_page_view.request_duration < 1
+    # another visit, the referer is set but should be ignored because
+    # the user didn't report to be on the page until now
+    @request.env['HTTP_REFERER'] = first_url
+    future = Time.now + 2*AnalyticsPlugin::TimeOnPageUpdateInterval
+    Time.stubs(:now).returns(future)
+    get :view_page, profile: @community.identifier, page: @community.articles.last.path.split('/')
+    assert_equal 2, @community.visits.count
   end
 
 end


=====================================
plugins/analytics/views/analytics_plugin/_body_ending.html.slim
=====================================
--- a/plugins/analytics/views/analytics_plugin/_body_ending.html.slim
+++ b/plugins/analytics/views/analytics_plugin/_body_ending.html.slim
@@ -1,6 +1,6 @@
 javascript:
   analytics.timeOnPage.baseUrl = #{url_for(controller: 'analytics_plugin/time_on_page').to_json}
-  analytics.timeOnPage.updateInterval = #{AnalyticsPlugin::TimeOnPageUpdateInterval.to_json}
+  analytics.timeOnPage.updateInterval = #{AnalyticsPlugin::TimeOnPageUpdateIntervalMs.to_json}
   analytics.requestId = #{request.env['action_dispatch.request_id'].to_json}
   analytics.init()
 


=====================================
plugins/analytics/views/analytics_plugin/stats/_table.html.slim
=====================================
--- /dev/null
+++ b/plugins/analytics/views/analytics_plugin/stats/_table.html.slim
@@ -0,0 +1,38 @@
+
+table#analytics-stats.table data-toggle='table' data-striped='true' data-sortable='true' data-icons-prefix='fa'
+  thead
+    - unless profile.analytics_anonymous?
+      th= t'analytics_plugin.views.stats.user'
+    th= t'analytics_plugin.views.stats.initial_time'
+    th= t'analytics_plugin.views.stats.pages'
+
+  tbody
+    - profile.visits.each do |visit|
+      tr
+        td= link_to visit.user.name, visit.user.url
+        td
+          div data-toggle="tooltip" data-title='#{l visit.initial_time}'
+            = time_ago_in_words(visit.initial_time)
+            |&nbsp
+            = _'ago'
+        td
+          - visit.page_views.each do |page_view|
+            = link_to page_view.url, page_view.url
+            | 
+            = "(#{distance_of_time_in_words page_view.time_on_page})"
+            | -> 
+
+javascript:
+  $('#analytics-stats').bootstrapTable({
+    striped: true,
+    columns: [
+      {sortable: true},
+      {sortable: true},
+      {sortable: true},
+    ],
+  })
+
+  $(document).ready(function() {
+    $('[data-toggle="tooltip"]').tooltip()
+  })
+


=====================================
plugins/analytics/views/analytics_plugin/stats/index.html.slim
=====================================
--- /dev/null
+++ b/plugins/analytics/views/analytics_plugin/stats/index.html.slim
@@ -0,0 +1,5 @@
+- content_for :head
+  = javascript_include_tag 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.8.1/bootstrap-table-all.min.js'
+  = stylesheet_link_tag 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.8.1/bootstrap-table.css'
+
+= render 'table'



View it on GitLab: https://gitlab.com/noosfero/noosfero/commit/492c3d63597701e331a22aad279e182c569f03a4
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listas.softwarelivre.org/pipermail/noosfero-dev/attachments/20150828/a4774378/attachment-0001.html>


More information about the Noosfero-dev mailing list