mitamirri 0.13.8 → 2.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/Capfile +4 -0
- data/Gemfile +29 -0
- data/README.rdoc +6 -55
- data/Rakefile +34 -21
- data/VERSION +1 -1
- data/app/controllers/admin/tracking/reports_controller.rb +78 -0
- data/app/controllers/admin/tracking/trackable_sessions_controller.rb +7 -0
- data/app/controllers/application_controller.rb +1 -8
- data/app/controllers/trackable_actions_controller.rb +0 -2
- data/app/helpers/application_helper.rb +21 -0
- data/app/helpers/layout_helper.rb +18 -0
- data/app/models/content_report.rb +35 -0
- data/app/models/content_stat.rb +4 -0
- data/app/models/destination.rb +4 -0
- data/app/models/intersite_traffic_report.rb +47 -0
- data/app/models/keyword_stat.rb +4 -0
- data/app/models/lead.rb +3 -0
- data/app/models/lead_stat.rb +5 -0
- data/app/models/leads_report.rb +32 -0
- data/app/models/location_stat.rb +37 -0
- data/app/models/referrer_stat.rb +4 -0
- data/app/models/report.rb +83 -0
- data/app/models/stat_base.rb +11 -0
- data/app/models/trackable_action.rb +114 -91
- data/app/models/trackable_base.rb +12 -0
- data/app/models/trackable_location.rb +7 -13
- data/app/models/trackable_session.rb +255 -171
- data/app/models/trackable_stat.rb +45 -27
- data/app/models/traffic_explorer_report.rb +92 -0
- data/app/models/traffic_summary_report.rb +142 -0
- data/app/models/user_agent_stat.rb +4 -0
- data/app/models/visit.rb +6 -0
- data/app/models/visit_stat.rb +5 -0
- data/app/models/visitor.rb +4 -0
- data/app/models/visitor_profile_report.rb +23 -0
- data/app/views/admin/tracking/reports/_content.html.erb +28 -0
- data/app/views/admin/tracking/reports/_conversion_rate.html.erb +30 -0
- data/app/views/admin/tracking/reports/_criteria.html.erb +33 -0
- data/app/views/admin/tracking/reports/_entrance_pages.html.erb +29 -0
- data/app/views/admin/tracking/reports/_exit_pages.html.erb +28 -0
- data/app/views/admin/tracking/reports/_explorer_criteria.html.erb +22 -0
- data/app/views/admin/tracking/reports/_explorer_summary.html.erb +22 -0
- data/app/views/admin/tracking/reports/_intersite_destinations.html.erb +28 -0
- data/app/views/admin/tracking/reports/_intersite_referrals.html.erb +30 -0
- data/app/views/admin/tracking/reports/_leads.html.erb +30 -0
- data/app/views/admin/tracking/reports/_locations.html.erb +47 -0
- data/app/views/admin/tracking/reports/_recent_visits.html.erb +33 -0
- data/app/views/admin/tracking/reports/_referring_keywords.html.erb +28 -0
- data/app/views/admin/tracking/reports/_referring_sites.html.erb +28 -0
- data/app/views/admin/tracking/reports/_traffic_summary.html.erb +26 -0
- data/app/views/admin/tracking/reports/_user_agents.html.erb +28 -0
- data/app/views/{trackable_sessions/_visits_graph.html.erb → admin/tracking/reports/_visits_by_kind.html.erb} +3 -3
- data/app/views/admin/tracking/reports/content.html.erb +12 -0
- data/app/views/admin/tracking/reports/explorer.html.erb +13 -0
- data/app/views/admin/tracking/reports/index.html.erb +16 -0
- data/app/views/admin/tracking/reports/intersite.html.erb +11 -0
- data/app/views/admin/tracking/reports/leads.html.erb +11 -0
- data/app/views/admin/tracking/reports/summary.html.erb +16 -0
- data/app/views/admin/tracking/reports/visitor_profile.html.erb +11 -0
- data/app/views/{trackable_sessions → admin/tracking/trackable_sessions}/show.html.erb +5 -4
- data/app/views/layouts/application.html.erb +51 -18
- data/config.ru +4 -0
- data/config/application.rb +13 -0
- data/config/boot.rb +13 -110
- data/config/cucumber.yml +10 -0
- data/config/deploy.rb +40 -0
- data/config/environment.rb +4 -23
- data/config/environments/development.rb +24 -13
- data/config/environments/production.rb +41 -20
- data/config/environments/test.rb +28 -24
- data/config/initializers/formats.rb +19 -0
- data/config/initializers/metric_fu.rb +9 -0
- data/config/initializers/secret_token.rb +7 -0
- data/config/initializers/session_store.rb +3 -10
- data/config/locales/en.yml +1 -1
- data/config/mongoid.yml +19 -0
- data/config/routes.rb +16 -10
- data/features/access_reports.feature +26 -0
- data/features/step_definitions/reports_steps.rb +9 -0
- data/features/step_definitions/web_steps.rb +219 -0
- data/features/support/env.rb +32 -0
- data/features/support/hooks.rb +1 -0
- data/features/support/paths.rb +33 -0
- data/features/traffic_summary_report.feature +43 -0
- data/init.rb +0 -7
- data/lib/mitamirri.rb +9 -12
- data/lib/mitamirri/engine.rb +7 -0
- data/lib/mitamirri/helper.rb +13 -29
- data/lib/mitamirri/railtie.rb +10 -0
- data/lib/tasks/cucumber.rake +60 -0
- data/lib/tasks/rcov.rake +44 -0
- data/mitamirri.gemspec +228 -100
- data/public/404.html +26 -0
- data/public/422.html +26 -0
- data/public/500.html +26 -0
- data/{config/database.yml → public/favicon.ico} +0 -0
- data/public/images/icons/add.png +0 -0
- data/public/images/icons/collapsed.gif +0 -0
- data/public/images/icons/delete.png +0 -0
- data/public/images/icons/drag.png +0 -0
- data/public/images/icons/edit.png +0 -0
- data/public/images/icons/expanded.gif +0 -0
- data/public/images/icons/help_icon.png +0 -0
- data/public/images/icons/link_icon.png +0 -0
- data/public/images/icons/move.png +0 -0
- data/public/images/icons/move_white.png +0 -0
- data/public/images/icons/note.png +0 -0
- data/public/images/icons/note_white.png +0 -0
- data/public/images/icons/notification_icon_sprite.png +0 -0
- data/public/images/icons/spinner.gif +0 -0
- data/public/images/icons/view.png +0 -0
- data/public/images/icons/warning.png +0 -0
- data/public/images/icons/warning_2.png +0 -0
- data/public/images/icons/warning_box.png +0 -0
- data/public/images/icons/warning_icon.png +0 -0
- data/public/images/icons/warning_white.png +0 -0
- data/public/images/layout/arrow_asc.png +0 -0
- data/public/images/layout/arrow_desc.png +0 -0
- data/public/images/layout/back.png +0 -0
- data/public/images/layout/black_bar.png +0 -0
- data/public/images/layout/branding.png +0 -0
- data/public/images/layout/breadcrumb_bg.png +0 -0
- data/public/images/layout/button_bg.png +0 -0
- data/public/images/layout/content_left_bg.png +0 -0
- data/public/images/layout/content_right_bg.png +0 -0
- data/public/images/layout/footer_bg.png +0 -0
- data/public/images/layout/h1_bg.png +0 -0
- data/public/images/layout/h2_bg.png +0 -0
- data/public/images/layout/h2_bg_for_table.png +0 -0
- data/public/images/layout/header_bg_grey.png +0 -0
- data/public/images/layout/header_bg_purple.png +0 -0
- data/public/images/layout/legend_bg.png +0 -0
- data/public/images/layout/menu_box_bg.png +0 -0
- data/public/images/layout/shadow_border.png +0 -0
- data/public/images/layout/shadow_border_2.png +0 -0
- data/public/images/layout/shadow_border_3.png +0 -0
- data/public/images/layout/shadow_border_4.png +0 -0
- data/public/images/layout/tab.png +0 -0
- data/public/images/layout/tab_active.png +0 -0
- data/public/images/layout/table_header.png +0 -0
- data/public/images/layout/text_field_bg.jpg +0 -0
- data/public/images/layout/text_field_error_bg.png +0 -0
- data/public/images/layout/th_bg.png +0 -0
- data/public/images/layout/th_bg_selected.png +0 -0
- data/public/images/menu_icons/content_report.png +0 -0
- data/public/images/menu_icons/content_report_on.png +0 -0
- data/public/images/menu_icons/funnel.png +0 -0
- data/public/images/menu_icons/funnel_on.png +0 -0
- data/public/images/menu_icons/intersite_traffic.png +0 -0
- data/public/images/menu_icons/intersite_traffic_on.png +0 -0
- data/public/images/menu_icons/leads.png +0 -0
- data/public/images/menu_icons/leads_on.png +0 -0
- data/public/images/menu_icons/traffic_explorer.png +0 -0
- data/public/images/menu_icons/traffic_explorer_on.png +0 -0
- data/public/images/menu_icons/traffic_summary.png +0 -0
- data/public/images/menu_icons/traffic_summary_on.png +0 -0
- data/public/images/menu_icons/visitor_profile.png +0 -0
- data/public/images/menu_icons/visitor_profile_on.png +0 -0
- data/public/index.html +8 -0
- data/public/javascripts/application.js +2 -0
- data/public/javascripts/controls.js +965 -0
- data/public/javascripts/dragdrop.js +974 -0
- data/public/javascripts/effects.js +1123 -0
- data/public/javascripts/prototype.js +6001 -0
- data/public/javascripts/rails.js +175 -0
- data/public/robots.txt +5 -0
- data/public/stylesheets/.gitkeep +0 -0
- data/public/stylesheets/application.css +876 -0
- data/public/stylesheets/core.css +1146 -0
- data/public/stylesheets/core_ie.css +52 -0
- data/public/stylesheets/csshover3.htc +14 -0
- data/public/stylesheets/mitamirri.css +37 -724
- data/public/stylesheets/mitamirri_print.css +3 -0
- data/script/cucumber +10 -0
- data/script/rails +6 -0
- data/spec/blueprints.rb +13 -0
- data/spec/helpers/application_helper_spec.rb +23 -35
- data/spec/{lib → models}/content_report_spec.rb +12 -8
- data/spec/{lib → models}/intersite_traffic_report_spec.rb +6 -9
- data/spec/{lib → models}/leads_report_spec.rb +11 -12
- data/spec/models/location_stat_spec.rb +18 -0
- data/spec/models/trackable_action_spec.rb +46 -14
- data/spec/models/trackable_base_spec.rb +27 -0
- data/spec/models/trackable_session_spec.rb +181 -57
- data/spec/{lib/session_report_spec.rb → models/traffic_explorer_report_spec.rb} +8 -25
- data/spec/spec_helper.rb +8 -28
- data/{lib/mitamirri/tasks.rb → tasks/mitamirri.rake} +6 -7
- data/vendor/plugins/.gitkeep +0 -0
- metadata +316 -77
- data/.gitignore +0 -26
- data/app/controllers/trackable_sessions_controller.rb +0 -100
- data/app/views/trackable_sessions/_keywords_graph.html.erb +0 -24
- data/app/views/trackable_sessions/_print_buttons.html.erb +0 -3
- data/app/views/trackable_sessions/_sessions.html.erb +0 -26
- data/app/views/trackable_sessions/_top_referrers.html.erb +0 -24
- data/app/views/trackable_sessions/_traffic_summary_all.html.erb +0 -64
- data/app/views/trackable_sessions/_traffic_summary_by_kind.html.erb +0 -48
- data/app/views/trackable_sessions/content.html.erb +0 -119
- data/app/views/trackable_sessions/explorer.html.erb +0 -67
- data/app/views/trackable_sessions/export.xls.erb +0 -5
- data/app/views/trackable_sessions/index.html.erb +0 -47
- data/app/views/trackable_sessions/intersite.html.erb +0 -97
- data/app/views/trackable_sessions/leads.html.erb +0 -98
- data/app/views/trackable_sessions/visitor_profile.html.erb +0 -114
- data/config/initializers/backtrace_silencers.rb +0 -7
- data/config/initializers/database.rb +0 -1
- data/config/initializers/inflections.rb +0 -10
- data/config/initializers/mime_types.rb +0 -5
- data/config/initializers/new_rails_defaults.rb +0 -21
- data/db/development.sqlite3 +0 -0
- data/db/migrate/20100810173533_create_trackable_sessions.rb +0 -23
- data/db/migrate/20100810173605_create_trackable_actions.rb +0 -20
- data/db/test.sqlite3 +0 -1
- data/lib/mitamirri/content_report.rb +0 -75
- data/lib/mitamirri/intersite_traffic_report.rb +0 -122
- data/lib/mitamirri/leads_report.rb +0 -90
- data/lib/mitamirri/session_report.rb +0 -219
- data/lib/mitamirri/stat_report.rb +0 -216
- data/lib/mitamirri/visitor_profile_report.rb +0 -127
- data/script/about +0 -4
- data/script/console +0 -3
- data/script/dbconsole +0 -3
- data/script/destroy +0 -3
- data/script/generate +0 -3
- data/script/performance/benchmarker +0 -3
- data/script/performance/profiler +0 -3
- data/script/plugin +0 -3
- data/script/runner +0 -3
- data/script/server +0 -3
- data/spec/controllers/trackable_actions_controller_spec.rb +0 -5
- data/spec/controllers/trackable_sessions_controller_spec.rb +0 -5
- data/spec/custom_matchers.rb +0 -23
- data/spec/lib/stat_report_spec.rb +0 -106
- data/spec/rcov.opts +0 -4
- data/spec/schema.rb +0 -34
- data/spec/spec.opts +0 -4
@@ -0,0 +1,12 @@
|
|
1
|
+
class TrackableBase
|
2
|
+
|
3
|
+
def self.dates_from_time_period(time_period="past 3 months")
|
4
|
+
start_date = TrackableAction.first.try(:created_at) || Time.zone.now
|
5
|
+
start_date = (Time.zone.now - 2.months).beginning_of_month if time_period == 'past 3 months'
|
6
|
+
start_date = (Time.zone.now - 5.months).beginning_of_month if time_period == 'past 6 months'
|
7
|
+
start_date = (Time.zone.now - 11.months).beginning_of_month if time_period == 'past 12 months'
|
8
|
+
end_date = Time.zone.now.end_of_month
|
9
|
+
[start_date, end_date]
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -1,19 +1,13 @@
|
|
1
|
-
class TrackableLocation
|
1
|
+
class TrackableLocation < TrackableBase
|
2
2
|
|
3
|
-
include
|
3
|
+
include Mongoid::Document
|
4
4
|
|
5
|
-
#
|
5
|
+
# Mongoid Setup ==============================================================================
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
# Scopes =========================================================================================
|
12
|
-
|
13
|
-
# Constants ======================================================================================
|
14
|
-
|
15
|
-
# Class Methods ==================================================================================
|
7
|
+
field :location
|
8
|
+
field :latitude
|
9
|
+
field :longitude
|
16
10
|
|
17
|
-
|
11
|
+
index :location, :unique => false
|
18
12
|
|
19
13
|
end
|
@@ -1,42 +1,57 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
1
|
+
# Tracks user activity to a given site.
|
2
|
+
class TrackableSession < TrackableBase
|
3
|
+
|
4
|
+
# Mongoid Config =================================================================================
|
5
|
+
|
6
|
+
include Mongoid::Document
|
7
|
+
include Mongoid::Timestamps
|
8
|
+
|
9
|
+
referenced_in :trackable_stat
|
10
|
+
references_many :trackable_actions
|
11
|
+
|
12
|
+
field :bounce, :type => Boolean
|
13
|
+
field :clickthrough_destination
|
14
|
+
field :duration, :type => Integer
|
15
|
+
field :entrance_page
|
16
|
+
field :exit_page
|
17
|
+
field :has_clicks, :type => Boolean
|
18
|
+
field :has_clickthroughs, :type => Boolean
|
19
|
+
field :has_conversions, :type => Boolean
|
20
|
+
field :has_mouseovers, :type => Boolean
|
21
|
+
field :has_scrolls, :type => Boolean
|
22
|
+
field :initial_request_url
|
23
|
+
field :ip_address
|
24
|
+
field :kind
|
25
|
+
field :location
|
26
|
+
field :new_visit, :type => Boolean
|
27
|
+
field :referrer
|
28
|
+
field :referring_keywords
|
29
|
+
field :session_id
|
30
|
+
field :site
|
31
|
+
field :spider, :type => Boolean
|
32
|
+
field :user_agent
|
33
|
+
field :views_count, :type => Integer
|
34
|
+
field :visit_kind
|
35
|
+
|
36
|
+
index :bounce, :unique => false
|
37
|
+
index :created_at, :unique => false
|
38
|
+
index :has_clicks, :unique => false
|
39
|
+
index :has_clickthroughs, :unique => false
|
40
|
+
index :has_mouseovers, :unique => false
|
41
|
+
index :has_scrolls, :unique => false
|
42
|
+
index :ip_address, :unique => false
|
43
|
+
index :kind, :unique => false
|
44
|
+
index :new_visit, :unique => false
|
45
|
+
index :referrer, :unique => false
|
46
|
+
index :session_id, :unique => false
|
47
|
+
index :site, :unique => false
|
48
|
+
index :spider, :unique => false
|
49
|
+
index :visit_kind, :unique => false
|
50
|
+
|
36
51
|
# Callbacks ======================================================================================
|
37
52
|
|
38
53
|
before_create :init
|
39
|
-
|
54
|
+
|
40
55
|
# Constants ======================================================================================
|
41
56
|
|
42
57
|
KINDS = ['direct', 'natural', 'paid', 'search']
|
@@ -44,65 +59,132 @@ class TrackableSession
|
|
44
59
|
|
45
60
|
# Scopes =========================================================================================
|
46
61
|
|
47
|
-
scope :by_ip_address, lambda { |ip| { :
|
48
|
-
scope :of_kind, lambda { |k| { :
|
49
|
-
scope :for_site, lambda { |s| { :
|
50
|
-
scope :for_month, lambda { |d| { :
|
51
|
-
scope :for_week, lambda { |d| { :
|
52
|
-
scope :for_date_range, lambda { |start_date,end_date| { :
|
53
|
-
scope :bounces, :
|
54
|
-
scope :direct_visits, :
|
55
|
-
scope :new_visits, :
|
56
|
-
scope :organic_visits, :
|
57
|
-
scope :ppc_visits, :
|
58
|
-
scope :spider_visits, :
|
59
|
-
scope :recent_visits, :
|
60
|
-
scope :return_visits, :
|
61
|
-
scope :search_visits, :
|
62
|
+
scope :by_ip_address, lambda { |ip| { :where => { :ip_address => ip } } }
|
63
|
+
scope :of_kind, lambda { |k| { :where => { :kind => k } } }
|
64
|
+
scope :for_site, lambda { |s| { :where => { :site => s } } }
|
65
|
+
scope :for_month, lambda { |d| { :where => { :created_at => { '$gte' => d.beginning_of_month, '$lte' => d.end_of_month } } } }
|
66
|
+
scope :for_week, lambda { |d| { :where => { :created_at => { '$gte' => d.beginning_of_week, '$lte' => d.end_of_week } } } }
|
67
|
+
scope :for_date_range, lambda { |start_date,end_date| { :where => { :created_at => { '$gte' => start_date.beginning_of_month, '$lte' => end_date.end_of_month } } } }
|
68
|
+
scope :bounces, :where => {:bounce => true}
|
69
|
+
scope :direct_visits, :where => { :kind => 'direct' }, :order => 'created_at'
|
70
|
+
scope :new_visits, :where => { :new_visit => true }, :order => 'created_at'
|
71
|
+
scope :organic_visits, :where => { :kind => 'natural' }, :order => 'created_at'
|
72
|
+
scope :ppc_visits, :where => { :kind => 'paid' }, :order => 'created_at'
|
73
|
+
scope :spider_visits, :where => { :spider => true }, :order => 'created_at'
|
74
|
+
scope :recent_visits, :where => { :created_at => { '$gte' => Time.zone.now.beginning_of_month }}, :order => 'created_at DESC', :limit => 25
|
75
|
+
scope :return_visits, :where => { :new_visit => false }, :order => 'created_at'
|
76
|
+
scope :search_visits, :where => { :kind => 'search' }, :order => 'created_at'
|
62
77
|
scope :with_any_actions
|
63
|
-
scope :with_clicks, :
|
64
|
-
scope :with_clickthroughs, :
|
65
|
-
scope :with_conversions, :
|
66
|
-
scope :with_leads, :
|
67
|
-
scope :with_mouseovers, :
|
68
|
-
scope :with_scrolls, :
|
69
|
-
scope :with_views, :
|
78
|
+
scope :with_clicks, :where => { :has_clicks => true }, :order => 'created_at'
|
79
|
+
scope :with_clickthroughs, :where => { :has_clickthroughs => true }
|
80
|
+
scope :with_conversions, :where => { :has_conversions => true }, :order => 'created_at'
|
81
|
+
scope :with_leads, :where => { :has_conversions => true }, :order => 'created_at'
|
82
|
+
scope :with_mouseovers, :where => { :has_mouseovers => true }, :order => 'created_at'
|
83
|
+
scope :with_scrolls, :where => { :has_scrolls => true }, :order => 'created_at'
|
84
|
+
scope :with_views, :where => { :views_count => { '$gte' => 1 } }, :order => 'created_at'
|
70
85
|
|
71
86
|
# Class Methods ==================================================================================
|
72
87
|
|
88
|
+
# Returns the conversion rate for sessions matching the specified arguments, ie: percentage of the total number of visits that were conversions.
|
89
|
+
#
|
90
|
+
# ==== Attributes
|
91
|
+
#
|
92
|
+
# * +:time_period+ - date range as a string: 'past 3 months', 'past 6 months', 'past 12 months'
|
93
|
+
# * +:site+ - name of a site
|
94
|
+
# * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search'
|
95
|
+
#
|
96
|
+
# ==== Examples
|
97
|
+
#
|
98
|
+
# TrackableSession.conversion_rate( :site => 'foo.com' )
|
73
99
|
def self.conversion_rate(args)
|
74
100
|
(TrackableSession.search(args).with_conversions.count.to_f / TrackableSession.search(args).count) * 100
|
75
101
|
end
|
76
|
-
|
102
|
+
|
103
|
+
# Returns a histogram for the number of clickthroughs to each referred site(s).
|
104
|
+
#
|
105
|
+
# ==== Attributes
|
106
|
+
#
|
107
|
+
# * +:time_period+ - date range as a string: 'past 3 months', 'past 6 months', 'past 12 months'
|
108
|
+
# * +:site+ - name of a site
|
109
|
+
# * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search'
|
110
|
+
#
|
111
|
+
# ==== Examples
|
112
|
+
#
|
113
|
+
# TrackableSession.clickthroughs_histogram( :site => 'foo.com' )
|
77
114
|
def self.clickthroughs_histogram(args)
|
78
|
-
conditions = TrackableSession.search(args).
|
79
|
-
TrackableSession.collection.group("function(x) { return { destination: x.clickthrough_destination }; }", conditions, { :count => 0}, "function(x,y){y.count++}"
|
115
|
+
conditions = TrackableSession.search(args).selector
|
116
|
+
TrackableSession.collection.group(:keyf => "function(x) { return { destination: x.clickthrough_destination }; }", :cond => conditions, :initial => { :count => 0}, :reduce => "function(x,y){y.count++}").inject({}){|h,k| h[k['destination']] = k['count'] unless k['destination'].blank?; h}
|
80
117
|
end
|
81
118
|
|
119
|
+
# Returns a histogram for the first page users visited for the specified site(s).
|
120
|
+
#
|
121
|
+
# ==== Attributes
|
122
|
+
#
|
123
|
+
# * +:time_period+ - date range as a string: 'past 3 months', 'past 6 months', 'past 12 months'
|
124
|
+
# * +:site+ - name of a site
|
125
|
+
# * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search'
|
126
|
+
#
|
127
|
+
# ==== Examples
|
128
|
+
#
|
129
|
+
# TrackableSession.entrance_pages_histogram( :site => 'foo.com' )
|
82
130
|
def self.entrance_pages_histogram(args)
|
83
|
-
conditions = TrackableSession.search(args).
|
84
|
-
TrackableSession.collection.group("function(x) { return { entrance_page: x.entrance_page }; }", conditions, { :count => 0}, "function(x,y){y.count++}"
|
131
|
+
conditions = TrackableSession.search(args).selector
|
132
|
+
TrackableSession.collection.group(:keyf => "function(x) { return { entrance_page: x.entrance_page }; }", :cond => conditions, :initial => { :count => 0}, :reduce => "function(x,y){y.count++}").inject({}){|h,k| h[k['entrance_page']] = k['count']; h}.sort{|a,b| a[1] <=> b[1]}.reverse
|
85
133
|
end
|
86
134
|
|
135
|
+
# Returns a histogram for the last page users visited for the specified site(s).
|
136
|
+
#
|
137
|
+
# ==== Attributes
|
138
|
+
#
|
139
|
+
# * +:time_period+ - date range as a string: 'past 3 months', 'past 6 months', 'past 12 months'
|
140
|
+
# * +:site+ - name of a site
|
141
|
+
# * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search'
|
142
|
+
#
|
143
|
+
# ==== Examples
|
144
|
+
#
|
145
|
+
# TrackableSession.exit_pages_histogram( :site => 'foo.com' )
|
87
146
|
def self.exit_pages_histogram(args)
|
88
|
-
conditions = TrackableSession.search(args).
|
89
|
-
TrackableSession.collection.group("function(x) { return { exit_page: x.exit_page }; }", conditions, { :count => 0}, "function(x,y){y.count++}"
|
147
|
+
conditions = TrackableSession.search(args).selector
|
148
|
+
TrackableSession.collection.group(:keyf => "function(x) { return { exit_page: x.exit_page }; }", :cond => conditions, :initial => { :count => 0}, :reduce => "function(x,y){y.count++}").inject({}){|h,k| h[k['exit_page']] = k['count']; h}.sort{|a,b| a[1] <=> b[1]}.reverse
|
90
149
|
end
|
91
150
|
|
151
|
+
# Returns a histogram for the search terms users used to find the specified site(s).
|
152
|
+
#
|
153
|
+
# ==== Attributes
|
154
|
+
#
|
155
|
+
# * +:time_period+ - date range as a string: 'past 3 months', 'past 6 months', 'past 12 months'
|
156
|
+
# * +:site+ - name of a site
|
157
|
+
# * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search'
|
158
|
+
#
|
159
|
+
# ==== Examples
|
160
|
+
#
|
161
|
+
# TrackableSession.keywords_histogram( :site => 'foo.com' )
|
92
162
|
def self.keywords_histogram(args)
|
93
|
-
conditions = TrackableSession.search(args).
|
94
|
-
TrackableSession.collection.group("function(x) { return { keyword: x.referring_keywords }; }", conditions, { :count => 0}, "function(x,y){y.count++}"
|
163
|
+
conditions = TrackableSession.search(args).selector
|
164
|
+
TrackableSession.collection.group(:keyf => "function(x) { return { keyword: x.referring_keywords }; }", :cond => conditions, :initial => { :count => 0}, :reduce => "function(x,y){y.count++}").inject({}){|h,k| h[k['keyword']] = k['count'] unless k['keyword'].blank?; h}
|
95
165
|
end
|
96
|
-
|
166
|
+
|
97
167
|
def self.kinds_for_select
|
98
168
|
[['All', 'all']] | TrackableSession::KINDS.sort.map{|k| [k.titleize, k]}
|
99
169
|
end
|
100
|
-
|
170
|
+
|
171
|
+
# Returns a histogram for the geocoded locations of visitors to the specified site(s).
|
172
|
+
#
|
173
|
+
# ==== Attributes
|
174
|
+
#
|
175
|
+
# * +:time_period+ - date range as a string: 'past 3 months', 'past 6 months', 'past 12 months'
|
176
|
+
# * +:site+ - name of a site
|
177
|
+
# * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search'
|
178
|
+
#
|
179
|
+
# ==== Examples
|
180
|
+
#
|
181
|
+
# TrackableSession.locations_histogram( :site => 'foo.com' )
|
101
182
|
def self.locations_histogram(args)
|
102
|
-
conditions = TrackableSession.search(args).
|
103
|
-
TrackableSession.collection.group("function(x) { return { location: x.location }; }", conditions, { :count => 0}, "function(x,y){y.count++}"
|
183
|
+
conditions = TrackableSession.search(args).selector
|
184
|
+
TrackableSession.collection.group(:keyf => "function(x) { return { location: x.location }; }", :cond => conditions, :initial => { :count => 0}, :reduce => "function(x,y){y.count++}").inject({}){|h,k| h[k['location']] = k['count'].to_i unless k['location'].blank? || k['location'] == 'Unknown'; h}
|
104
185
|
end
|
105
|
-
|
186
|
+
|
187
|
+
# Returns a human-readable user agent for the browser.
|
106
188
|
def self.parsed_user_agent(user_agent)
|
107
189
|
begin
|
108
190
|
_ua = Agent.new(user_agent)
|
@@ -112,89 +194,73 @@ class TrackableSession
|
|
112
194
|
end
|
113
195
|
_user_agent
|
114
196
|
end
|
115
|
-
|
197
|
+
|
198
|
+
# Returns a histogram for the referrers for site(s) matching the specified arguments.
|
199
|
+
#
|
200
|
+
# ==== Attributes
|
201
|
+
#
|
202
|
+
# * +:time_period+ - date range as a string: 'past 3 months', 'past 6 months', 'past 12 months'
|
203
|
+
# * +:site+ - name of a site
|
204
|
+
# * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search'
|
205
|
+
#
|
206
|
+
# ==== Examples
|
207
|
+
#
|
208
|
+
# TrackableSession.referrers_histogram( :site => 'foo.com' )
|
116
209
|
def self.referrers_histogram(args)
|
117
|
-
conditions = TrackableSession.search(args).
|
118
|
-
TrackableSession.collection.group("function(x) { return { referrer: x.referrer }; }", conditions, { :count => 0}, "function(x,y){y.count++}"
|
210
|
+
conditions = TrackableSession.search(args).selector
|
211
|
+
TrackableSession.collection.group(:keyf => "function(x) { return { referrer: x.referrer }; }", :cond => conditions, :initial => { :count => 0}, :reduce => "function(x,y){y.count++}").inject({}){|h,k| h[k['referrer']] = k['count'] unless k['referrer'].blank?; h}
|
119
212
|
end
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
args[:end_date] = Time.zone.now
|
140
|
-
end
|
141
|
-
if args[:time_period]
|
142
|
-
if args[:visit_kind] == 'all'
|
143
|
-
if args[:site] == 'all sites'
|
144
|
-
TrackableSession.send("with_#{args[:action_kind]}").for_date_range(args[:start_date], args[:end_date])
|
145
|
-
else
|
146
|
-
TrackableSession.for_site(args[:site]).send("with_#{args[:action_kind]}").for_date_range(args[:start_date], args[:end_date])
|
147
|
-
end
|
148
|
-
else
|
149
|
-
if args[:site] == 'all sites'
|
150
|
-
TrackableSession.of_kind(args[:visit_kind]).send("with_#{args[:action_kind]}").for_date_range(args[:start_date], args[:end_date])
|
151
|
-
else
|
152
|
-
TrackableSession.for_site(args[:site]).of_kind(args[:visit_kind]).send("with_#{args[:action_kind]}").for_date_range(args[:start_date], args[:end_date])
|
153
|
-
end
|
154
|
-
end
|
155
|
-
else
|
156
|
-
if args[:visit_kind] == 'all'
|
157
|
-
if args[:site] == 'all sites'
|
158
|
-
TrackableSession.send("with_#{args[:action_kind]}")
|
159
|
-
else
|
160
|
-
TrackableSession.for_site(args[:site]).send("with_#{args[:action_kind]}")
|
161
|
-
end
|
162
|
-
else
|
163
|
-
if args[:site] == 'all sites'
|
164
|
-
TrackableSession.of_kind(args[:visit_kind]).send("with_#{args[:action_kind]}")
|
165
|
-
else
|
166
|
-
TrackableSession.for_site(args[:site]).of_kind(args[:visit_kind]).send("with_#{args[:action_kind]}")
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
213
|
+
|
214
|
+
# Returns a scope based on time period, site, and visit kind. Null arguments returns all.
|
215
|
+
#
|
216
|
+
# ==== Attributes
|
217
|
+
#
|
218
|
+
# * +:time_period+ - date range as a string: 'past 3 months', 'past 6 months', 'past 12 months'
|
219
|
+
# * +:site+ - name of a site
|
220
|
+
# * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search'
|
221
|
+
#
|
222
|
+
# ==== Examples
|
223
|
+
#
|
224
|
+
# TrackableSession.search( :site => 'foo.com' )
|
225
|
+
def self.search(args)
|
226
|
+
(args[:start_date], args[:end_date]) = dates_from_time_period(args[:time_period])
|
227
|
+
sessions = args[:time_period] ? TrackableSession.for_date_range(args[:start_date], args[:end_date]) : TrackableSession.all
|
228
|
+
sessions = sessions.send("with_#{args[:action_kind].pluralize.downcase}") if args[:action_kind]
|
229
|
+
sessions = sessions.for_site(args[:site].downcase) unless args[:site].downcase == 'all sites'
|
230
|
+
sessions = sessions.of_kind(args[:visit_kind].downcase) if args[:visit_kind] && args[:visit_kind].downcase != 'all'
|
231
|
+
sessions.desc(:created_at)
|
170
232
|
end
|
171
|
-
|
172
|
-
#
|
233
|
+
|
234
|
+
# Returns a scope based on site and visit kind only.
|
235
|
+
#
|
236
|
+
# ==== Attributes
|
237
|
+
#
|
238
|
+
# * +:site+ - name of a site
|
239
|
+
# * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search'
|
240
|
+
#
|
241
|
+
# ==== Examples
|
242
|
+
#
|
243
|
+
# TrackableSession.search_without_date( :site => 'foo.com' )
|
173
244
|
def self.search_without_date(args = {})
|
174
|
-
args
|
175
|
-
args
|
176
|
-
args
|
177
|
-
args[:action_kind] = args[:action_kind].pluralize
|
178
|
-
args[:time_period] ||= 'past 3 months'
|
179
|
-
[:site, :action_kind, :visit_kind].each{|a| args[a] = args[a].downcase}
|
180
|
-
if args[:visit_kind] == 'all'
|
181
|
-
if args[:site] == 'all sites'
|
182
|
-
TrackableSession.send("with_#{args[:action_kind]}")
|
183
|
-
else
|
184
|
-
TrackableSession.for_site(args[:site]).send("with_#{args[:action_kind]}")
|
185
|
-
end
|
186
|
-
else
|
187
|
-
if args[:site] == 'all sites'
|
188
|
-
TrackableSession.of_kind(args[:visit_kind]).send("with_#{args[:action_kind]}")
|
189
|
-
else
|
190
|
-
TrackableSession.for_site(args[:site]).of_kind(args[:visit_kind]).send("with_#{args[:action_kind]}")
|
191
|
-
end
|
192
|
-
end
|
245
|
+
args = args.clone
|
246
|
+
args.delete(:time_period)
|
247
|
+
self.search(args)
|
193
248
|
end
|
194
249
|
|
250
|
+
# Returns a histogram for the user agents for site(s) matching the specified arguments.
|
251
|
+
#
|
252
|
+
# ==== Attributes
|
253
|
+
#
|
254
|
+
# * +:time_period+ - date range as a string: 'past 3 months', 'past 6 months', 'past 12 months'
|
255
|
+
# * +:site+ - name of a site
|
256
|
+
# * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search'
|
257
|
+
#
|
258
|
+
# ==== Examples
|
259
|
+
#
|
260
|
+
# TrackableSession.user_agents_histogram( :site => 'foo.com' )
|
195
261
|
def self.user_agents_histogram(args)
|
196
|
-
conditions = TrackableSession.search(args).
|
197
|
-
_histogram = TrackableSession.collection.group("function(x) { return { user_agent: x.user_agent }; }", conditions, { :count => 0}, "function(x,y){y.count++}"
|
262
|
+
conditions = TrackableSession.search(args).selector
|
263
|
+
_histogram = TrackableSession.collection.group(:keyf => "function(x) { return { user_agent: x.user_agent }; }", :cond => conditions, :initial => { :count => 0}, :reduce => "function(x,y){y.count++}")
|
198
264
|
_final = {}
|
199
265
|
_histogram.each do |ua|
|
200
266
|
_ua = parsed_user_agent(ua['user_agent'])
|
@@ -203,22 +269,26 @@ class TrackableSession
|
|
203
269
|
end
|
204
270
|
_final
|
205
271
|
end
|
206
|
-
|
272
|
+
|
207
273
|
# Instance Methods ===============================================================================
|
208
274
|
|
275
|
+
# Returns the number of non-view actions for this session.
|
209
276
|
def actions
|
210
277
|
self.trackable_actions.count - self.trackable_actions.views.count
|
211
278
|
end
|
212
|
-
|
279
|
+
|
280
|
+
# Returns true if this is a new visit.
|
213
281
|
def detect_new_visit
|
214
|
-
TrackableSession.
|
282
|
+
TrackableSession.where(:ip_address => self.ip_address) ? false : true
|
215
283
|
end
|
216
|
-
|
284
|
+
|
285
|
+
# Returns this session's duration in X minutes or Y seconds.
|
217
286
|
def hr_duration
|
218
287
|
return 0 unless self.duration
|
219
288
|
self.duration > 60 ? sprintf("%.1f minutes", self.duration / 60.0) : sprintf("%.1f seconds", self.duration)
|
220
289
|
end
|
221
|
-
|
290
|
+
|
291
|
+
# Initializes a new session.
|
222
292
|
def init
|
223
293
|
self.bounce = true
|
224
294
|
self.kind ||= self.kind_by_referrer
|
@@ -226,13 +296,15 @@ class TrackableSession
|
|
226
296
|
self.referring_keywords = self.sanitize_referring_keywords
|
227
297
|
self.spider ||= spider_visit?
|
228
298
|
begin
|
299
|
+
raise ArgumentError, "No IP address available" unless self.ip_address
|
229
300
|
_location = Geokit::Geocoders::MultiGeocoder.geocode(self.ip_address)
|
230
301
|
self.location ||= _location.success? ? "#{_location.city}, #{_location.state}" : "Unknown"
|
231
302
|
rescue
|
232
303
|
self.location = "Unknown"
|
233
304
|
end
|
234
305
|
end
|
235
|
-
|
306
|
+
|
307
|
+
# Returns whether this session was initiated by a direct (bookmark or typed URL), search, paid (landing page), or natural (non-search link) referrer.
|
236
308
|
def kind_by_referrer
|
237
309
|
return "direct" unless self.referrer
|
238
310
|
unless self.referrer.blank?
|
@@ -241,42 +313,55 @@ class TrackableSession
|
|
241
313
|
end
|
242
314
|
"natural"
|
243
315
|
end
|
244
|
-
|
316
|
+
|
317
|
+
# Returns the number of page views associated with this session.
|
245
318
|
def pageviews
|
246
319
|
self.trackable_actions.views.count
|
247
320
|
end
|
248
321
|
|
322
|
+
# Returns this session's human-readable user agent.
|
249
323
|
def parsed_user_agent
|
250
324
|
TrackableSession.parsed_user_agent(self.user_agent)
|
251
325
|
end
|
252
|
-
|
326
|
+
|
327
|
+
# Returns the date of the last visit if this user visited before.
|
253
328
|
def last_visit_date
|
254
329
|
return nil if previous_visits_count.zero?
|
255
|
-
TrackableSession.by_ip_address(self.ip_address).
|
330
|
+
TrackableSession.by_ip_address(self.ip_address).asc(:created_at).only(:created_at).map{|s| s.created_at}.sort[-2]
|
256
331
|
end
|
257
|
-
|
332
|
+
|
333
|
+
# Returns the number of times this user has been here before.
|
258
334
|
def previous_visits_count
|
259
335
|
TrackableSession.by_ip_address(self.ip_address).count - 1
|
260
336
|
end
|
261
|
-
|
337
|
+
|
338
|
+
# Unescapes referring keywords for display.
|
262
339
|
def sanitize_referring_keywords
|
263
340
|
self.referring_keywords.to_s.gsub('+',' ')
|
264
341
|
end
|
265
|
-
|
266
|
-
#
|
342
|
+
|
343
|
+
# Updates this session with whatever the user just did.
|
344
|
+
#
|
345
|
+
# ==== Attributes
|
346
|
+
#
|
347
|
+
# * +:action_kind+ - action as a string: 'click', 'clickthrough', 'conversion', 'mouseover', 'scroll', 'view'
|
348
|
+
# * +:destination+ - clickthrough destination
|
349
|
+
# * +:last_url+ - the referring URL
|
350
|
+
#
|
351
|
+
# ==== Examples
|
352
|
+
#
|
353
|
+
# trackable_session.touch( 'click', 'cnn.com', 'foo.com/cnn' )
|
267
354
|
def touch(action_kind = nil, destination = nil, last_url = nil)
|
268
355
|
if action_kind && action_kind == 'scroll'
|
269
356
|
self.update_attributes(
|
270
357
|
:has_scrolls => true,
|
271
358
|
:bounce => self.trackable_actions.count <= 1,
|
272
|
-
:updated_at => Time.zone.now,
|
273
359
|
:duration => Time.zone.now - self.created_at
|
274
360
|
)
|
275
361
|
elsif action_kind && action_kind == 'click'
|
276
362
|
self.update_attributes(
|
277
363
|
:has_clicks => true,
|
278
364
|
:bounce => self.trackable_actions.count <= 1,
|
279
|
-
:updated_at => Time.zone.now,
|
280
365
|
:duration => Time.zone.now - self.created_at
|
281
366
|
)
|
282
367
|
elsif action_kind && action_kind == 'clickthrough'
|
@@ -284,21 +369,18 @@ class TrackableSession
|
|
284
369
|
:has_clickthroughs => true,
|
285
370
|
:clickthrough_destination => destination,
|
286
371
|
:bounce => false,
|
287
|
-
:updated_at => Time.zone.now,
|
288
372
|
:duration => Time.zone.now - self.created_at
|
289
373
|
)
|
290
374
|
elsif action_kind && action_kind == 'conversion'
|
291
375
|
self.update_attributes(
|
292
376
|
:has_conversions => true,
|
293
377
|
:bounce => self.trackable_actions.count <= 1,
|
294
|
-
:updated_at => Time.zone.now,
|
295
378
|
:duration => Time.zone.now - self.created_at
|
296
379
|
)
|
297
380
|
elsif action_kind && action_kind == 'mouseover'
|
298
381
|
self.update_attributes(
|
299
382
|
:has_mouseovers => true,
|
300
383
|
:bounce => self.trackable_actions.count <= 1,
|
301
|
-
:updated_at => Time.zone.now,
|
302
384
|
:duration => Time.zone.now - self.created_at
|
303
385
|
)
|
304
386
|
else
|
@@ -307,11 +389,13 @@ class TrackableSession
|
|
307
389
|
end
|
308
390
|
touch_stat
|
309
391
|
end
|
310
|
-
|
392
|
+
|
393
|
+
# Returns whether this session is new or existing.
|
311
394
|
def visit_type
|
312
395
|
self.new_visit? ? "New" : "Returning"
|
313
396
|
end
|
314
397
|
|
398
|
+
# Upserts stats associated with this session. Called every time this session is touched.
|
315
399
|
def touch_stat
|
316
400
|
# Upsert associated stat
|
317
401
|
if trackable_stat = TrackableStat.by_site(self.site).by_date(self.created_at).first
|
@@ -321,9 +405,9 @@ class TrackableSession
|
|
321
405
|
trackable_stat.touch(self, self.trackable_actions.last)
|
322
406
|
end
|
323
407
|
end
|
324
|
-
|
408
|
+
|
325
409
|
private
|
326
|
-
|
410
|
+
|
327
411
|
def ppc_visit?(url)
|
328
412
|
begin
|
329
413
|
_params = URI.parse(url).query.to_s.downcase
|
@@ -339,7 +423,7 @@ class TrackableSession
|
|
339
423
|
return true if _params.include?('cpc') # Generic
|
340
424
|
return false
|
341
425
|
end
|
342
|
-
|
426
|
+
|
343
427
|
def spider_visit?
|
344
428
|
_spider = true
|
345
429
|
return false if self.user_agent == "Unknown" || self.user_agent.nil?
|
@@ -348,5 +432,5 @@ class TrackableSession
|
|
348
432
|
end
|
349
433
|
_spider
|
350
434
|
end
|
351
|
-
|
435
|
+
|
352
436
|
end
|