mitamirri 0.13.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/.document +5 -0
  2. data/.gitignore +26 -0
  3. data/README.rdoc +117 -0
  4. data/Rakefile +26 -0
  5. data/VERSION +1 -0
  6. data/app/controllers/application_controller.rb +10 -0
  7. data/app/controllers/trackable_actions_controller.rb +10 -0
  8. data/app/controllers/trackable_sessions_controller.rb +100 -0
  9. data/app/helpers/application_helper.rb +2 -0
  10. data/app/models/trackable_action.rb +193 -0
  11. data/app/models/trackable_location.rb +19 -0
  12. data/app/models/trackable_session.rb +352 -0
  13. data/app/models/trackable_stat.rb +64 -0
  14. data/app/views/layouts/application.html.erb +20 -0
  15. data/app/views/trackable_sessions/_keywords_graph.html.erb +24 -0
  16. data/app/views/trackable_sessions/_print_buttons.html.erb +3 -0
  17. data/app/views/trackable_sessions/_sessions.html.erb +26 -0
  18. data/app/views/trackable_sessions/_top_referrers.html.erb +24 -0
  19. data/app/views/trackable_sessions/_traffic_summary_all.html.erb +64 -0
  20. data/app/views/trackable_sessions/_traffic_summary_by_kind.html.erb +48 -0
  21. data/app/views/trackable_sessions/_visits_graph.html.erb +25 -0
  22. data/app/views/trackable_sessions/content.html.erb +119 -0
  23. data/app/views/trackable_sessions/explorer.html.erb +67 -0
  24. data/app/views/trackable_sessions/export.xls.erb +5 -0
  25. data/app/views/trackable_sessions/index.html.erb +47 -0
  26. data/app/views/trackable_sessions/intersite.html.erb +97 -0
  27. data/app/views/trackable_sessions/leads.html.erb +98 -0
  28. data/app/views/trackable_sessions/show.html.erb +113 -0
  29. data/app/views/trackable_sessions/visitor_profile.html.erb +114 -0
  30. data/config/boot.rb +110 -0
  31. data/config/database.yml +0 -0
  32. data/config/environment.rb +24 -0
  33. data/config/environments/development.rb +17 -0
  34. data/config/environments/production.rb +28 -0
  35. data/config/environments/test.rb +31 -0
  36. data/config/initializers/backtrace_silencers.rb +7 -0
  37. data/config/initializers/database.rb +1 -0
  38. data/config/initializers/inflections.rb +10 -0
  39. data/config/initializers/mime_types.rb +5 -0
  40. data/config/initializers/new_rails_defaults.rb +21 -0
  41. data/config/initializers/session_store.rb +15 -0
  42. data/config/locales/en.yml +5 -0
  43. data/config/routes.rb +11 -0
  44. data/db/development.sqlite3 +0 -0
  45. data/db/migrate/20100810173533_create_trackable_sessions.rb +23 -0
  46. data/db/migrate/20100810173605_create_trackable_actions.rb +20 -0
  47. data/db/test.sqlite3 +1 -0
  48. data/doc/README_FOR_APP +2 -0
  49. data/init.rb +8 -0
  50. data/lib/mitamirri/content_report.rb +75 -0
  51. data/lib/mitamirri/helper.rb +106 -0
  52. data/lib/mitamirri/intersite_traffic_report.rb +122 -0
  53. data/lib/mitamirri/leads_report.rb +90 -0
  54. data/lib/mitamirri/session_report.rb +219 -0
  55. data/lib/mitamirri/stat_report.rb +216 -0
  56. data/lib/mitamirri/tasks.rb +27 -0
  57. data/lib/mitamirri/visitor_profile_report.rb +127 -0
  58. data/lib/mitamirri.rb +15 -0
  59. data/log/development.log +0 -0
  60. data/log/production.log +0 -0
  61. data/log/server.log +0 -0
  62. data/log/test.log +0 -0
  63. data/mitamirri.gemspec +125 -0
  64. data/public/stylesheets/mitamirri.css +736 -0
  65. data/script/about +4 -0
  66. data/script/console +3 -0
  67. data/script/dbconsole +3 -0
  68. data/script/destroy +3 -0
  69. data/script/generate +3 -0
  70. data/script/performance/benchmarker +3 -0
  71. data/script/performance/profiler +3 -0
  72. data/script/plugin +3 -0
  73. data/script/runner +3 -0
  74. data/script/server +3 -0
  75. data/spec/controllers/trackable_actions_controller_spec.rb +5 -0
  76. data/spec/controllers/trackable_sessions_controller_spec.rb +5 -0
  77. data/spec/custom_matchers.rb +23 -0
  78. data/spec/helpers/application_helper_spec.rb +57 -0
  79. data/spec/lib/content_report_spec.rb +37 -0
  80. data/spec/lib/intersite_traffic_report_spec.rb +51 -0
  81. data/spec/lib/leads_report_spec.rb +46 -0
  82. data/spec/lib/session_report_spec.rb +107 -0
  83. data/spec/lib/stat_report_spec.rb +106 -0
  84. data/spec/models/trackable_action_spec.rb +42 -0
  85. data/spec/models/trackable_session_spec.rb +154 -0
  86. data/spec/rcov.opts +4 -0
  87. data/spec/schema.rb +34 -0
  88. data/spec/spec.opts +4 -0
  89. data/spec/spec_helper.rb +32 -0
  90. metadata +155 -0
@@ -0,0 +1,90 @@
1
+ module Mitamirri
2
+
3
+ class LeadsReport
4
+
5
+ # Search params
6
+ attr_accessor :site
7
+ attr_accessor :time_period
8
+ attr_accessor :start_date
9
+ attr_accessor :end_date
10
+
11
+ # Stat attributes
12
+
13
+ # Initialization
14
+
15
+ def initialize(args = {})
16
+ args.each{|k,v| self.send("#{k}=",v) if self.respond_to?(k)}
17
+ self.time_period = args[:time_period] || 'past 6 months'
18
+ self.start_date = self.dates.first
19
+ self.end_date = self.dates.last
20
+ end
21
+
22
+ # Generate an array of dates spanning the appropriate time period.
23
+ def dates
24
+ return @dates if @dates
25
+ @dates = []
26
+ case self.time_period.downcase
27
+ when 'past month'
28
+ _increment = 4
29
+ when 'past 3 months'
30
+ _increment = 12
31
+ when 'past 6 months'
32
+ _increment = 24
33
+ when 'past 12 months'
34
+ _increment = 52
35
+ else 'all time'
36
+ _increment = 104
37
+ end
38
+
39
+ (1.._increment).each{ |i| @dates << (Time.zone.now - i.weeks).beginning_of_week }
40
+ @dates.reverse!
41
+ @dates << Time.zone.now
42
+ @dates
43
+ end
44
+
45
+ # Graphing objects
46
+
47
+ def leads(args)
48
+ _leads = []
49
+ _leads << Lead.new(:stats => lead_stats(args))
50
+ _leads
51
+ end
52
+
53
+ def lead_stats(args)
54
+ _lead_stats = []
55
+ dates.each do |date|
56
+ _total_sessions = TrackableSession.search_without_date(args).for_week(date).count
57
+ _total_conversions = TrackableSession.search_without_date(args).for_week(date).with_conversions.count
58
+ _conversion_rate = (_total_conversions.to_f / _total_sessions) * 100
59
+ _lead_stats << LeadStat.new(:date => date, :leads => _total_conversions, :conversion_rate => sprintf("%0.1f",_conversion_rate).to_f)
60
+ end
61
+ _lead_stats
62
+ end
63
+
64
+ # Inner stat classes
65
+
66
+ class Lead
67
+ attr_accessor :stats
68
+ def initialize(args)
69
+ args.each{ |k,v| self.send("#{k}=", v) }
70
+ end
71
+ end
72
+
73
+ class LeadStat
74
+ attr_accessor :date
75
+ attr_accessor :leads
76
+ attr_accessor :conversion_rate
77
+
78
+ def initialize(args)
79
+ args.each{ |k,v| self.send("#{k}=", v) }
80
+ end
81
+
82
+ def short_date
83
+ self.date.to_s(:concise)
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
@@ -0,0 +1,219 @@
1
+ module Mitamirri
2
+
3
+ class SessionReport
4
+
5
+ # Search params
6
+ attr_accessor :action_kind
7
+ attr_accessor :site
8
+ attr_accessor :time_period
9
+ attr_accessor :visit_kind
10
+
11
+ # Initialization
12
+
13
+ def initialize(args = {})
14
+ args.each{|k,v| self.send("#{k}=",v) if self.respond_to?(k)}
15
+ self.time_period = args[:time_period] || 'past 6 months'
16
+ self.sessions
17
+ end
18
+
19
+ def criteria
20
+ _criteria = self.sessions.to_hash
21
+ _criteria.delete(:sort)
22
+ _criteria
23
+ end
24
+
25
+ def sessions
26
+ @sessions ||= TrackableSession.search(
27
+ :action_kind => self.action_kind,
28
+ :site => self.site,
29
+ :time_period => self.time_period,
30
+ :visit_kind => self.visit_kind
31
+ )
32
+ end
33
+
34
+ # Generate an array of dates spanning the appropriate time period.
35
+ def dates
36
+ return @dates if @dates
37
+ @dates = []
38
+ case self.time_period
39
+ when 'past month'
40
+ _increment = 1
41
+ when 'past 3 months'
42
+ _increment = 2
43
+ when 'past 6 months'
44
+ _increment = 5
45
+ when 'past 12 months'
46
+ _increment = 11
47
+ else 'all time'
48
+ _increment = 24
49
+ end
50
+
51
+ (1.._increment).each{ |i| @dates << (Time.zone.now - i.months).beginning_of_month }
52
+ @dates.reverse!
53
+ @dates << Time.zone.now.end_of_month
54
+ @dates
55
+ end
56
+
57
+ # Graphing data
58
+ def self.keywords_by_frequency(args)
59
+ TrackableSession.keywords_histogram(args).inject([]){|a,v| a << KeywordStat.new(:keyword => v[0], :count => v[1]); a}.sort{|a,b| a.count <=> b.count}.reverse[0..24]
60
+ end
61
+
62
+ def self.top_referrers(args)
63
+ TrackableSession.referrers_histogram(args).inject([]){|a,v| a << ReferrerStat.new(:referrer => v[0], :count => v[1]); a}.sort{|a,b| a.count <=> b.count}.reverse[0..24]
64
+ end
65
+
66
+ def visits(args)
67
+ _visits = []
68
+ _visits << Visit.new(:kind => "#{args[:visit_kind].titleize} Visits", :stats => visit_stats(args))
69
+ _visits
70
+ end
71
+
72
+ def visit_stats(args)
73
+ _visit_stats = []
74
+ dates.each do |date|
75
+ _visit_stats << VisitStat.new(:date => date, :visits => TrackableSession.search_without_date(args).for_month(date).count)
76
+ end
77
+ _visit_stats
78
+ end
79
+
80
+ # Statistics
81
+
82
+ def average_pages_per_visit
83
+ sprintf("%.1f", total_pageviews / total_visits.to_f)
84
+ end
85
+
86
+ def average_time_on_site
87
+ average = total_duration / total_visits.to_f
88
+ average > 60 ? sprintf("%.1f minutes", average / 60.0) : sprintf("%.1f seconds", average)
89
+ end
90
+
91
+ def bounce_rate
92
+ bounce_rate = total_bounces / total_visits.to_f
93
+ sprintf("%.1f%", bounce_rate * 100)
94
+ end
95
+
96
+ def conversion_rate
97
+ conversion_rate = total_conversions / total_visits.to_f
98
+ sprintf("%.1f%", conversion_rate * 100)
99
+ end
100
+
101
+ def total_bounces
102
+ @total_bounces ||= self.sessions.bounces.count
103
+ end
104
+
105
+ def total_clickthroughs
106
+ @total_clickthroughs ||= self.sessions.with_clickthroughs.count
107
+ end
108
+
109
+ def total_clickthroughs_percentage
110
+ sprintf("%.1f%", (total_clickthroughs / total_visits.to_f) * 100)
111
+ end
112
+
113
+ def total_conversions
114
+ @total_conversions ||= self.sessions.with_conversions.count
115
+ end
116
+
117
+ def total_direct_visits
118
+ @total_direct_visits ||= self.sessions.direct_visits.count
119
+ end
120
+
121
+ def total_duration
122
+ @total_duration ||= TrackableSession.collection.group(["site"], self.criteria, {:duration => 0}, "function(doc,prev) { prev.duration += doc.duration}", true).map{|x| x['duration']}.sum.to_i
123
+ end
124
+
125
+ def total_new_visits
126
+ @total_new_visits ||= self.sessions.new_visits.count
127
+ end
128
+
129
+ def total_return_visits
130
+ @total_return_visits ||= total_visits - total_new_visits
131
+ end
132
+
133
+ def total_organic_visits
134
+ @total_organic_visits ||= self.sessions.organic_visits.count
135
+ end
136
+
137
+ def total_pageviews
138
+ @total_pageviews ||= TrackableSession.collection.group(["site"], self.criteria, {:views_count => 0}, "function(doc,prev) { prev.views_count += doc.views_count}", true).map{|x| x['views_count']}.sum.to_i
139
+ end
140
+
141
+ def total_ppc_visits
142
+ @total_ppc_visits ||= self.sessions.ppc_visits.count
143
+ end
144
+
145
+ def total_search_visits
146
+ @total_search_visits ||= self.sessions.search_visits.count
147
+ end
148
+
149
+ def total_direct_visits_percentage
150
+ sprintf("%.1f%", (total_direct_visits / total_visits.to_f) * 100)
151
+ end
152
+
153
+ def total_organic_visits_percentage
154
+ sprintf("%.1f%", (total_organic_visits / total_visits.to_f) * 100)
155
+ end
156
+
157
+ def total_new_visits_percentage
158
+ sprintf("%.1f%", (total_new_visits / total_visits.to_f) * 100)
159
+ end
160
+
161
+ def total_ppc_visits_percentage
162
+ sprintf("%.1f%", (total_ppc_visits / total_visits.to_f) * 100)
163
+ end
164
+
165
+ def total_return_visits_percentage
166
+ sprintf("%.1f%", (total_return_visits / total_visits.to_f) * 100)
167
+ end
168
+
169
+ def total_search_visits_percentage
170
+ sprintf("%.1f%", (total_search_visits / total_visits.to_f) * 100)
171
+ end
172
+
173
+ def total_visits
174
+ @total_visits ||= self.sessions.count
175
+ end
176
+
177
+ # Inner stat classes
178
+ class KeywordStat
179
+ attr_accessor :keyword
180
+ attr_accessor :count
181
+ def initialize(args)
182
+ args.each{ |k,v| self.send("#{k}=", v) }
183
+ end
184
+ end
185
+
186
+ class ReferrerStat
187
+ attr_accessor :referrer
188
+ attr_accessor :count
189
+ def initialize(args)
190
+ args.each{ |k,v| self.send("#{k}=", v) }
191
+ end
192
+ end
193
+
194
+ class Visit
195
+ attr_accessor :kind
196
+ attr_accessor :date
197
+ attr_accessor :stats
198
+ def initialize(args)
199
+ args.each{ |k,v| self.send("#{k}=", v) }
200
+ end
201
+ end
202
+
203
+ class VisitStat
204
+ attr_accessor :date
205
+ attr_accessor :visits
206
+
207
+ def initialize(args)
208
+ args.each{ |k,v| self.send("#{k}=", v) }
209
+ end
210
+
211
+ def short_date
212
+ self.date.to_s(:month_year)
213
+ end
214
+
215
+ end
216
+
217
+ end
218
+
219
+ end
@@ -0,0 +1,216 @@
1
+ module Mitamirri
2
+
3
+ class StatReport
4
+
5
+ # Search params
6
+ attr_accessor :action_kind
7
+ attr_accessor :site
8
+ attr_accessor :time_period
9
+ attr_accessor :visit_kind
10
+
11
+ # Initialization
12
+
13
+ def initialize(args = {})
14
+ args.each{|k,v| self.send("#{k}=",v) if self.respond_to?(k)}
15
+ self.time_period = args[:time_period] || 'past 6 months'
16
+ self.stats
17
+ end
18
+
19
+ def stats
20
+ if self.site && self.site.downcase != 'all sites'
21
+ @stats ||= TrackableStat.by_site(self.site).for_date_range(dates.first, dates.last.end_of_month)
22
+ else
23
+ @stats ||= TrackableStat.for_date_range(dates.first, dates.last.end_of_month)
24
+ end
25
+ end
26
+
27
+ # Generate an array of dates spanning the appropriate time period.
28
+ def dates
29
+ return @dates if @dates
30
+ @dates = []
31
+ case self.time_period
32
+ when 'past month'
33
+ _increment = 1
34
+ when 'past 3 months'
35
+ _increment = 2
36
+ when 'past 6 months'
37
+ _increment = 5
38
+ when 'past 12 months'
39
+ _increment = 11
40
+ else 'all time'
41
+ _increment = 24
42
+ end
43
+
44
+ (1.._increment).each{ |i| @dates << (Time.zone.now - i.months).beginning_of_month }
45
+ @dates.reverse!
46
+ @dates << Time.zone.now.end_of_month
47
+ @dates
48
+ end
49
+
50
+ # Graphing data
51
+ def self.keywords_by_frequency(args)
52
+ TrackableSession.keywords_histogram(args).inject([]){|a,v| a << KeywordStat.new(:keyword => v[0], :count => v[1]); a}.sort{|a,b| a.count <=> b.count}.reverse[0..24]
53
+ end
54
+
55
+ def self.top_referrers(args)
56
+ TrackableSession.referrers_histogram(args).inject([]){|a,v| a << ReferrerStat.new(:referrer => v[0], :count => v[1]); a}.sort{|a,b| a.count <=> b.count}.reverse[0..24]
57
+ end
58
+
59
+ def visits(args)
60
+ _visits = []
61
+ _visits << Visit.new(:kind => 'All', :stats => visit_stats(args))
62
+ _visits << Visit.new(:kind => 'Direct Traffic', :stats => visit_stats(args.merge(:visit_kind => 'direct')))
63
+ _visits << Visit.new(:kind => 'Referring Sites', :stats => visit_stats(args.merge(:visit_kind => 'natural')))
64
+ _visits << Visit.new(:kind => 'Organic Search', :stats => visit_stats(args.merge(:visit_kind => 'search')))
65
+ _visits << Visit.new(:kind => 'Paid Search', :stats => visit_stats(args.merge(:visit_kind => 'paid')))
66
+ _visits
67
+ end
68
+
69
+ def visit_stats(args)
70
+ _visit_stats = []
71
+ dates.each do |date|
72
+ _visit_stats << VisitStat.new(:date => date, :visits => TrackableSession.search_without_date(args).for_month(date).count)
73
+ end
74
+ _visit_stats
75
+ end
76
+
77
+ # Statistics
78
+
79
+ def average_pages_per_visit
80
+ sprintf("%.1f", total_pageviews / total_visits.to_f)
81
+ end
82
+
83
+ def average_time_on_site
84
+ average = total_duration / total_visits.to_f
85
+ average > 60 ? sprintf("%.1f minutes", average / 60.0) : sprintf("%.1f seconds", average)
86
+ end
87
+
88
+ def bounce_rate
89
+ bounce_rate = total_bounces / total_visits.to_f
90
+ sprintf("%.1f%", bounce_rate * 100)
91
+ end
92
+
93
+ def conversion_rate
94
+ conversion_rate = total_conversions / total_visits.to_f
95
+ sprintf("%.1f%", conversion_rate * 100)
96
+ end
97
+
98
+ def total_bounces
99
+ @total_bounces ||= stats.fields(:bounces).map{|s| s.bounces}.sum
100
+ end
101
+
102
+ def total_clickthroughs
103
+ @total_clickthroughs ||= stats.fields(:clickthroughs).map{|s| s.clickthroughs}.sum
104
+ end
105
+
106
+ def total_clickthroughs_percentage
107
+ sprintf("%.1f%", (total_clickthroughs / total_visits.to_f) * 100)
108
+ end
109
+
110
+ def total_conversions
111
+ @total_conversions ||= stats.fields(:conversions).map{|s| s.conversions}.sum
112
+ end
113
+
114
+ def total_direct_visits
115
+ @total_direct_visits ||= stats.fields(:direct_visits).map{|s| s.direct_visits}.sum
116
+ end
117
+
118
+ def total_direct_visits_percentage
119
+ sprintf("%.1f%", (total_direct_visits / total_visits.to_f) * 100)
120
+ end
121
+
122
+ def total_duration
123
+ @total_duration ||= stats.fields(:duration).map{|s| s.duration}.sum
124
+ end
125
+
126
+ def total_new_visits
127
+ @total_new_visits ||= stats.fields(:new_visits).map{|s| s.new_visits}.sum
128
+ end
129
+
130
+ def total_new_visits_percentage
131
+ sprintf("%.1f%", (total_new_visits / total_visits.to_f) * 100)
132
+ end
133
+
134
+ def total_organic_visits
135
+ @total_organic_visits ||= stats.fields(:organic_visits).map{|s| s.organic_visits}.sum
136
+ end
137
+
138
+ def total_organic_visits_percentage
139
+ sprintf("%.1f%", (total_organic_visits / total_visits.to_f) * 100)
140
+ end
141
+
142
+ def total_pageviews
143
+ @total_pageviews ||= stats.fields(:pageviews).map{|s| s.pageviews}.sum
144
+ end
145
+
146
+ def total_ppc_visits
147
+ @total_ppc_visits ||= stats.fields(:ppc_visits).map{|s| s.ppc_visits}.sum
148
+ end
149
+
150
+ def total_ppc_visits_percentage
151
+ sprintf("%.1f%", (total_ppc_visits / total_visits.to_f) * 100)
152
+ end
153
+
154
+ def total_return_visits
155
+ @total_return_visits ||= stats.fields(:return_visits).map{|s| s.return_visits}.sum
156
+ end
157
+
158
+ def total_return_visits_percentage
159
+ sprintf("%.1f%", (total_return_visits / total_visits.to_f) * 100)
160
+ end
161
+
162
+ def total_search_visits
163
+ @total_search_visits ||= stats.fields(:search_visits).map{|s| s.search_visits}.sum
164
+ end
165
+
166
+ def total_search_visits_percentage
167
+ sprintf("%.1f%", (total_search_visits / total_visits.to_f) * 100)
168
+ end
169
+
170
+ def total_visits
171
+ @total_visits ||= stats.fields(:visits).map{|s| s.visits}.sum
172
+ end
173
+
174
+ # Inner stat classes
175
+ class KeywordStat
176
+ attr_accessor :keyword
177
+ attr_accessor :count
178
+ def initialize(args)
179
+ args.each{ |k,v| self.send("#{k}=", v) }
180
+ end
181
+ end
182
+
183
+ class ReferrerStat
184
+ attr_accessor :referrer
185
+ attr_accessor :count
186
+ def initialize(args)
187
+ args.each{ |k,v| self.send("#{k}=", v) }
188
+ end
189
+ end
190
+
191
+ class Visit
192
+ attr_accessor :kind
193
+ attr_accessor :date
194
+ attr_accessor :stats
195
+ def initialize(args)
196
+ args.each{ |k,v| self.send("#{k}=", v) }
197
+ end
198
+ end
199
+
200
+ class VisitStat
201
+ attr_accessor :date
202
+ attr_accessor :visits
203
+
204
+ def initialize(args)
205
+ args.each{ |k,v| self.send("#{k}=", v) }
206
+ end
207
+
208
+ def short_date
209
+ self.date.to_s(:month_year)
210
+ end
211
+
212
+ end
213
+
214
+ end
215
+
216
+ end
@@ -0,0 +1,27 @@
1
+ # require 'mitamirri/tasks' to add tasks to the host application.
2
+
3
+ namespace :mitamirri do
4
+
5
+ desc "Sync migrations and other files from Mitamirri."
6
+ task :install do
7
+ dir = Gem.searcher.find('mitamirri').full_gem_path
8
+ system "rsync -ruv #{dir}/public/stylesheets public/"
9
+ system "rsync -ruv #{dir}/config/initializers/database.rb config/initializers/"
10
+ puts
11
+ puts "Mitamarri file sync complete."
12
+ puts "Run rake mitamirri:override to install local views and controllers to override default behaviour."
13
+ puts
14
+ end
15
+
16
+ desc "Copy default view and controller files from Mitamirri to the host application."
17
+ task :override do
18
+ dir = Gem.searcher.find('mitamirri').full_gem_path
19
+ system "rsync -ruv #{dir}/app/controllers/trackable_actions_controller.rb app/controllers/"
20
+ system "rsync -ruv #{dir}/app/controllers/trackable_sessions_controller.rb app/controllers/"
21
+ system "rsync -ruv #{dir}/app/views/trackable_sessions app/views/"
22
+ puts
23
+ puts "Mitamarri views and controllers copied and ready to override."
24
+ puts
25
+ end
26
+
27
+ end
@@ -0,0 +1,127 @@
1
+ module Mitamirri
2
+
3
+ class VisitorProfileReport
4
+
5
+ # Search params
6
+ attr_accessor :action_kind
7
+ attr_accessor :site
8
+ attr_accessor :time_period
9
+ attr_accessor :visit_kind
10
+
11
+ # Initialization
12
+
13
+ def initialize(args = {})
14
+ args.each{|k,v| self.send("#{k}=",v) if self.respond_to?(k)}
15
+ self.time_period = args[:time_period] || 'past 6 months'
16
+ self.sessions
17
+ end
18
+
19
+ def criteria
20
+ _criteria = self.sessions.to_hash
21
+ _criteria.delete(:sort)
22
+ _criteria
23
+ end
24
+
25
+ def sessions
26
+ @sessions ||= TrackableSession.search(
27
+ :action_kind => self.action_kind,
28
+ :site => self.site,
29
+ :time_period => self.time_period,
30
+ :visit_kind => self.visit_kind
31
+ )
32
+ end
33
+
34
+ # Generate an array of dates spanning the appropriate time period.
35
+ def dates
36
+ return @dates if @dates
37
+ @dates = []
38
+ case self.time_period
39
+ when 'past month'
40
+ _increment = 1
41
+ when 'past 3 months'
42
+ _increment = 2
43
+ when 'past 6 months'
44
+ _increment = 5
45
+ when 'past 12 months'
46
+ _increment = 11
47
+ else 'all time'
48
+ _increment = 24
49
+ end
50
+
51
+ (1.._increment).each{ |i| @dates << (Time.zone.now - i.months).beginning_of_month }
52
+ @dates.reverse!
53
+ @dates << Time.zone.now.end_of_month
54
+ @dates
55
+ end
56
+
57
+ # Graphing data
58
+
59
+ def locations_by_frequency(args)
60
+ TrackableSession.locations_histogram(args).inject([]){|a,v| a << LocationStat.new(:name => v[0], :count => v[1]); a}.sort{|a,b| a.count <=> b.count}.reverse[0..24]
61
+ end
62
+
63
+ def user_agents_by_frequency(args)
64
+ TrackableSession.user_agents_histogram(args).inject([]){|a,v| a << UserAgentStat.new(:user_agent => v[0], :count => v[1]); a}.sort{|a,b| a.count <=> b.count}.reverse[0..24]
65
+ end
66
+
67
+ # Inner stat classes
68
+
69
+ class Visitor
70
+ attr_accessor :user_agent_stats
71
+ attr_accessor :location_stats
72
+ def initialize(args)
73
+ args.each{ |k,v| self.send("#{k}=", v) }
74
+ end
75
+ end
76
+
77
+ class UserAgentStat
78
+ attr_accessor :user_agent
79
+ attr_accessor :count
80
+ def initialize(args)
81
+ args.each{ |k,v| self.send("#{k}=", v) }
82
+ end
83
+ end
84
+
85
+ class LocationStat
86
+
87
+ attr_accessor :name
88
+ attr_accessor :latitude
89
+ attr_accessor :longitude
90
+ attr_accessor :count
91
+
92
+ def initialize(args)
93
+ args.each{ |k,v| self.send("#{k}=", v) }
94
+ geocode
95
+ end
96
+
97
+ def geocode
98
+ if _location = TrackableLocation.where(:location => self.name).first
99
+ self.latitude = _location.latitude
100
+ self.longitude = _location.longitude
101
+ else
102
+ begin
103
+ _coords = Geokit::Geocoders::MultiGeocoder.geocode(self.name)
104
+ rescue
105
+ end
106
+ if _coords && _coords.success
107
+ self.latitude = _coords.lat
108
+ self.longitude = _coords.lng
109
+ TrackableLocation.create(:location => self.name, :latitude => self.latitude, :longitude => self.longitude)
110
+ end
111
+ end
112
+ end
113
+
114
+ def geocoded?
115
+ self.latitude && self.longitude
116
+ end
117
+
118
+ def sanitized_name
119
+ self.name.gsub(/'/,"\\'")
120
+ end
121
+
122
+ end
123
+
124
+
125
+ end
126
+
127
+ end
data/lib/mitamirri.rb ADDED
@@ -0,0 +1,15 @@
1
+ module Mitamirri
2
+ require 'mitamirri'
3
+ require 'mitamirri/session_report'
4
+
5
+ # Detects the ability of the host application to output reports to PDF format.
6
+ def self.pdf_output_enabled?
7
+ @pdf_output_enabled ||= false
8
+ begin
9
+ @pdf_output_enabled = Rails.configuration.middleware.include?('PDFKit::Middleware')
10
+ rescue
11
+ end
12
+ @pdf_output_enabled
13
+ end
14
+
15
+ end
File without changes
File without changes
data/log/server.log ADDED
File without changes
data/log/test.log ADDED
File without changes