mitamirri 0.13.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +26 -0
- data/README.rdoc +117 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/app/controllers/application_controller.rb +10 -0
- data/app/controllers/trackable_actions_controller.rb +10 -0
- data/app/controllers/trackable_sessions_controller.rb +100 -0
- data/app/helpers/application_helper.rb +2 -0
- data/app/models/trackable_action.rb +193 -0
- data/app/models/trackable_location.rb +19 -0
- data/app/models/trackable_session.rb +352 -0
- data/app/models/trackable_stat.rb +64 -0
- data/app/views/layouts/application.html.erb +20 -0
- data/app/views/trackable_sessions/_keywords_graph.html.erb +24 -0
- data/app/views/trackable_sessions/_print_buttons.html.erb +3 -0
- data/app/views/trackable_sessions/_sessions.html.erb +26 -0
- data/app/views/trackable_sessions/_top_referrers.html.erb +24 -0
- data/app/views/trackable_sessions/_traffic_summary_all.html.erb +64 -0
- data/app/views/trackable_sessions/_traffic_summary_by_kind.html.erb +48 -0
- data/app/views/trackable_sessions/_visits_graph.html.erb +25 -0
- data/app/views/trackable_sessions/content.html.erb +119 -0
- data/app/views/trackable_sessions/explorer.html.erb +67 -0
- data/app/views/trackable_sessions/export.xls.erb +5 -0
- data/app/views/trackable_sessions/index.html.erb +47 -0
- data/app/views/trackable_sessions/intersite.html.erb +97 -0
- data/app/views/trackable_sessions/leads.html.erb +98 -0
- data/app/views/trackable_sessions/show.html.erb +113 -0
- data/app/views/trackable_sessions/visitor_profile.html.erb +114 -0
- data/config/boot.rb +110 -0
- data/config/database.yml +0 -0
- data/config/environment.rb +24 -0
- data/config/environments/development.rb +17 -0
- data/config/environments/production.rb +28 -0
- data/config/environments/test.rb +31 -0
- data/config/initializers/backtrace_silencers.rb +7 -0
- data/config/initializers/database.rb +1 -0
- data/config/initializers/inflections.rb +10 -0
- data/config/initializers/mime_types.rb +5 -0
- data/config/initializers/new_rails_defaults.rb +21 -0
- data/config/initializers/session_store.rb +15 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +11 -0
- data/db/development.sqlite3 +0 -0
- data/db/migrate/20100810173533_create_trackable_sessions.rb +23 -0
- data/db/migrate/20100810173605_create_trackable_actions.rb +20 -0
- data/db/test.sqlite3 +1 -0
- data/doc/README_FOR_APP +2 -0
- data/init.rb +8 -0
- data/lib/mitamirri/content_report.rb +75 -0
- data/lib/mitamirri/helper.rb +106 -0
- data/lib/mitamirri/intersite_traffic_report.rb +122 -0
- data/lib/mitamirri/leads_report.rb +90 -0
- data/lib/mitamirri/session_report.rb +219 -0
- data/lib/mitamirri/stat_report.rb +216 -0
- data/lib/mitamirri/tasks.rb +27 -0
- data/lib/mitamirri/visitor_profile_report.rb +127 -0
- data/lib/mitamirri.rb +15 -0
- data/log/development.log +0 -0
- data/log/production.log +0 -0
- data/log/server.log +0 -0
- data/log/test.log +0 -0
- data/mitamirri.gemspec +125 -0
- data/public/stylesheets/mitamirri.css +736 -0
- data/script/about +4 -0
- data/script/console +3 -0
- data/script/dbconsole +3 -0
- data/script/destroy +3 -0
- data/script/generate +3 -0
- data/script/performance/benchmarker +3 -0
- data/script/performance/profiler +3 -0
- data/script/plugin +3 -0
- data/script/runner +3 -0
- data/script/server +3 -0
- data/spec/controllers/trackable_actions_controller_spec.rb +5 -0
- data/spec/controllers/trackable_sessions_controller_spec.rb +5 -0
- data/spec/custom_matchers.rb +23 -0
- data/spec/helpers/application_helper_spec.rb +57 -0
- data/spec/lib/content_report_spec.rb +37 -0
- data/spec/lib/intersite_traffic_report_spec.rb +51 -0
- data/spec/lib/leads_report_spec.rb +46 -0
- data/spec/lib/session_report_spec.rb +107 -0
- data/spec/lib/stat_report_spec.rb +106 -0
- data/spec/models/trackable_action_spec.rb +42 -0
- data/spec/models/trackable_session_spec.rb +154 -0
- data/spec/rcov.opts +4 -0
- data/spec/schema.rb +34 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +32 -0
- 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
|
data/log/development.log
ADDED
File without changes
|
data/log/production.log
ADDED
File without changes
|
data/log/server.log
ADDED
File without changes
|
data/log/test.log
ADDED
File without changes
|