gricer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +84 -0
- data/Rakefile +49 -0
- data/app/assets/images/gricer/fluid/breadcrumb.png +0 -0
- data/app/assets/javascripts/gricer.js.coffee +85 -0
- data/app/assets/javascripts/gricer_backend_jquery.js.coffee +352 -0
- data/app/assets/javascripts/jquery.flot.js +2599 -0
- data/app/assets/javascripts/jquery.flot.pie.js +750 -0
- data/app/assets/javascripts/jquery.flot.resize.js +60 -0
- data/app/assets/javascripts/jquery.flot.symbol.js +70 -0
- data/app/assets/javascripts/worldmap.js +146 -0
- data/app/assets/stylesheets/gricer/fluid-jquery-ui.css.scss +1298 -0
- data/app/assets/stylesheets/gricer/fluid.css.scss +240 -0
- data/app/assets/stylesheets/gricer/helpers/css3.css.scss +21 -0
- data/app/controllers/gricer/base_controller.rb +141 -0
- data/app/controllers/gricer/capture_controller.rb +42 -0
- data/app/controllers/gricer/dashboard_controller.rb +18 -0
- data/app/controllers/gricer/requests_controller.rb +42 -0
- data/app/controllers/gricer/sessions_controller.rb +24 -0
- data/app/helpers/gricer/base_helper.rb +22 -0
- data/app/models/gricer/agent.rb +789 -0
- data/app/models/gricer/request.rb +239 -0
- data/app/models/gricer/session.rb +433 -0
- data/app/views/gricer/capture/index.html.erb +1 -0
- data/app/views/gricer/dashboard/_menu.html.erb +10 -0
- data/app/views/gricer/dashboard/_overview.html.erb +33 -0
- data/app/views/gricer/dashboard/index.html.erb +19 -0
- data/config/routes.rb +51 -0
- data/lib/gricer.rb +36 -0
- data/lib/gricer/action_controller/base.rb +28 -0
- data/lib/gricer/action_controller/track.rb +132 -0
- data/lib/gricer/active_model/statistics.rb +167 -0
- data/lib/gricer/config.rb +125 -0
- data/lib/gricer/engine.rb +9 -0
- data/lib/gricer/localization.rb +3 -0
- data/lib/tasks/gricer_tasks.rake +92 -0
- data/spec/controllers/gricer/base_controller_spec.rb +207 -0
- data/spec/controllers/gricer/capture_controller_spec.rb +44 -0
- data/spec/controllers/gricer/dashboard_controller_spec.rb +44 -0
- data/spec/controllers/gricer/requests_controller_spec.rb +36 -0
- data/spec/controllers/gricer/sessions_controller_spec.rb +37 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +9 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/assets/stylesheets/dashboard.css +4 -0
- data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/spec/dummy/app/assets/stylesheets/sessions.css +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +23 -0
- data/spec/dummy/app/controllers/dashboard_controller.rb +19 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/helpers/dashboard_helper.rb +2 -0
- data/spec/dummy/app/views/dashboard/index.html.erb +236 -0
- data/spec/dummy/app/views/layouts/application.html.erb +16 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +48 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/cucumber.yml +9 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +27 -0
- data/spec/dummy/config/environments/production.rb +51 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +12 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +11 -0
- data/spec/dummy/db/schema.rb +241 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/helpers/gricer/base_helper_spec.rb +28 -0
- data/spec/lib/gricer/action_controller/track_spec.rb +63 -0
- data/spec/models/gricer/agent_spec.rb +829 -0
- data/spec/models/gricer/request_spec.rb +145 -0
- data/spec/models/gricer/session_spec.rb +209 -0
- data/spec/routing/capture_routes_spec.rb +6 -0
- data/spec/routing/dashboard_routes_spec.rb +9 -0
- data/spec/routing/requests_routes_spec.rb +90 -0
- data/spec/routing/sessions_routes_spec.rb +115 -0
- data/spec/spec_helper.rb +23 -0
- metadata +185 -0
@@ -0,0 +1,239 @@
|
|
1
|
+
module Gricer
|
2
|
+
# ActiveRecord Model for Request Statistics
|
3
|
+
# @attr [Gricer::Session] session
|
4
|
+
# The current value of the associated session.
|
5
|
+
#
|
6
|
+
# @attr [Gricer::Agent] agent
|
7
|
+
# The current value of the associated agent.
|
8
|
+
#
|
9
|
+
# @attr [String] host
|
10
|
+
# The current value of the host requested.
|
11
|
+
#
|
12
|
+
# @attr [String] path
|
13
|
+
# The current value of the path requested.
|
14
|
+
#
|
15
|
+
# @attr [String] method
|
16
|
+
# The current value of the method requested.
|
17
|
+
#
|
18
|
+
# @attr [String] protocol
|
19
|
+
# The current value of the protocol requested.
|
20
|
+
#
|
21
|
+
# @attr [String] controller
|
22
|
+
# The current value of the controller requested.
|
23
|
+
#
|
24
|
+
# @attr [String] action
|
25
|
+
# The current value of the action requested.
|
26
|
+
#
|
27
|
+
# @attr [String] format
|
28
|
+
# The current value of the format requested.
|
29
|
+
#
|
30
|
+
# @attr [String] param_id
|
31
|
+
# The current value of the http GET/POST id parameter requested.
|
32
|
+
#
|
33
|
+
# @attr [Integer] user_id
|
34
|
+
# The current id of the user logged in.
|
35
|
+
#
|
36
|
+
# @see Gricer::ActionController::Base#gricer_user_id
|
37
|
+
#
|
38
|
+
# @attr [Integer] status_code
|
39
|
+
# The current value of the HTTP status returned.
|
40
|
+
#
|
41
|
+
# @attr [String] content_type
|
42
|
+
# The current value of the content type returned.
|
43
|
+
#
|
44
|
+
# @attr [String] body_size
|
45
|
+
# The current size of the body returned.
|
46
|
+
#
|
47
|
+
# @attr [String] system_time
|
48
|
+
# The current value of the system time elapsed processing this request.
|
49
|
+
#
|
50
|
+
# @attr [String] user_time
|
51
|
+
# The current value of the user time elapsed processing this request.
|
52
|
+
#
|
53
|
+
# @attr [String] total_time
|
54
|
+
# The current value of the total time elapsed processing this request.
|
55
|
+
#
|
56
|
+
# @attr [String] real_time
|
57
|
+
# The current value of the real time elapsed processing this request.
|
58
|
+
#
|
59
|
+
# @attr [Boolean] javascript
|
60
|
+
# The current value of the javascript capability of the requesting agent.
|
61
|
+
#
|
62
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
63
|
+
#
|
64
|
+
# @attr [Integer] window_width
|
65
|
+
# The current value of the width in pixels of the requesting agent's window.
|
66
|
+
#
|
67
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
68
|
+
#
|
69
|
+
# @attr [Integer] window_height
|
70
|
+
# The current value of the height in pixels of the requesting agent's window.
|
71
|
+
#
|
72
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
73
|
+
#
|
74
|
+
# @attr [String] referer_protocol
|
75
|
+
# The current value of the protocol of the referering page.
|
76
|
+
#
|
77
|
+
# @attr [String] referer_host
|
78
|
+
# The current value of the host of the referering page.
|
79
|
+
#
|
80
|
+
# @attr [String] referer_path
|
81
|
+
# The current value of the path of the referering page.
|
82
|
+
#
|
83
|
+
# @attr [String] referer_params
|
84
|
+
# The current value of the params of the referering page.
|
85
|
+
#
|
86
|
+
# @attr [String] search_engine
|
87
|
+
# The current value of the search engine name refering to get to this request.
|
88
|
+
#
|
89
|
+
# @attr [String] search_query
|
90
|
+
# The current value of the search query refering to get to this request.
|
91
|
+
#
|
92
|
+
# @attr [Boolean] is_first_in_session
|
93
|
+
# The current value of the first in session flag.
|
94
|
+
# This is true if it is the first request within a Gricer::Session.
|
95
|
+
#
|
96
|
+
# @attr [String] locale_major
|
97
|
+
# The current value of the locale responded (major locale only)
|
98
|
+
#
|
99
|
+
# @attr [String] locale_minor
|
100
|
+
# The current value of the locale responded (major locale only)
|
101
|
+
#
|
102
|
+
# @attr [String] locale
|
103
|
+
# The current value of the locale responded
|
104
|
+
#
|
105
|
+
class Request < ::ActiveRecord::Base
|
106
|
+
set_table_name "#{::Gricer::config.table_name_prefix}requests"
|
107
|
+
include ActiveModel::Statistics
|
108
|
+
|
109
|
+
belongs_to :session, class_name: 'Gricer::Session', counter_cache: true
|
110
|
+
belongs_to :agent, class_name: 'Gricer::Agent', counter_cache: true
|
111
|
+
|
112
|
+
before_create :init_session
|
113
|
+
|
114
|
+
# Filter out anything that is not a Browser or MobileBrowser
|
115
|
+
# @return [ActiveRecord::Relation]
|
116
|
+
def self.browsers
|
117
|
+
includes("agent")
|
118
|
+
.where("\"#{Agent.table_name}\".\"agent_class_id\" IN (?)", [0x1000, 0x2000])
|
119
|
+
end
|
120
|
+
|
121
|
+
# Filter out anything that has not the first_in_session flag
|
122
|
+
# @return [ActiveRecord::Relation]
|
123
|
+
def self.only_first_in_session
|
124
|
+
where('is_first_in_session = ?', true)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Store the ip address from which the request was sent for init_session
|
128
|
+
# @see #init_session
|
129
|
+
def ip_address=(ip)
|
130
|
+
@ip_address = ip
|
131
|
+
end
|
132
|
+
|
133
|
+
# Find or Create Gricer::Agent corrosponding to the given user agent string as given in the HTTP header
|
134
|
+
#
|
135
|
+
# @param agent_header [String] A user agent string as in a HTTP header
|
136
|
+
# @return [Gricer::Agent]
|
137
|
+
def agent_header=(agent_header)
|
138
|
+
self.agent = Agent.find_or_create_by_request_header agent_header
|
139
|
+
end
|
140
|
+
|
141
|
+
# Parse the Ruby on Rails request to fill attributes
|
142
|
+
def request=(request)
|
143
|
+
self.ip_address = request.remote_ip
|
144
|
+
self.agent_header = request.headers['HTTP_USER_AGENT']
|
145
|
+
self.referer = request.headers['HTTP_X_FORWARDED_REFERER'] || request.headers['HTTP_REFERER']
|
146
|
+
|
147
|
+
self.host = request.host
|
148
|
+
self.path = request.path
|
149
|
+
self.method = request.request_method
|
150
|
+
self.protocol = request.protocol.sub(/[:\/]*$/, '').upcase
|
151
|
+
self.locale = I18n.locale
|
152
|
+
|
153
|
+
@request_locale = request.headers['HTTP_ACCEPT_LANGUAGE'].try(:split, ',').try(:first)
|
154
|
+
|
155
|
+
logger.debug I18n.locale
|
156
|
+
end
|
157
|
+
|
158
|
+
def locale=(locale)
|
159
|
+
self.locale_major, self.locale_minor = locale.try(:to_s).try(:downcase).try(:split, '-')
|
160
|
+
end
|
161
|
+
|
162
|
+
def locale
|
163
|
+
if locale_minor
|
164
|
+
"#{locale_major}-#{locale_minor}"
|
165
|
+
else
|
166
|
+
locale_major
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Parse the referer to fill referer and search engine attributes
|
171
|
+
#
|
172
|
+
# @param referer [String] The Referer as given in HTTP request
|
173
|
+
def referer=(referer)
|
174
|
+
if referer
|
175
|
+
void, self.referer_protocol, self.referer_host, self.referer_path, self.referer_params = referer.match(/([A-Za-z0-9]*):\/\/([^\/]*)([^\?]*)[\?]?(.*)/).to_a
|
176
|
+
|
177
|
+
# Sanatize/Normalize referer values
|
178
|
+
self.referer_protocol = referer_protocol.try(:upcase)
|
179
|
+
self.referer_host = referer_host.try(:downcase)
|
180
|
+
self.referer_path = '/' if referer_path.blank?
|
181
|
+
self.referer_params = nil if referer_params.blank?
|
182
|
+
params = CGI::parse(referer_params) unless referer_params.blank?
|
183
|
+
|
184
|
+
# Detect Search Engines
|
185
|
+
if referer_host =~ /^www\.google(?:\.com?)?(?:\.[a-z]{2})?$/ and ['/search', '/url'].include? referer_path
|
186
|
+
self.search_engine = 'Google'
|
187
|
+
self.search_query = params['q'].try(:first)
|
188
|
+
elsif referer_host == 'www.bing.com' and referer_path == '/search'
|
189
|
+
self.search_engine = 'Bing'
|
190
|
+
self.search_query = params['q'].try(:first)
|
191
|
+
elsif referer_host =~ /search\.yahoo\.com$/ and referer_path =~ /\/search;/
|
192
|
+
self.search_engine = 'Yahoo'
|
193
|
+
self.search_query = params['p'].try(:first)
|
194
|
+
elsif referer_host == 'www.baidu.com' and referer_path == '/s'
|
195
|
+
self.search_engine = 'Baidu'
|
196
|
+
self.search_query = params['wd'].try(:first)
|
197
|
+
elsif referer_host =~ /ask\.com$/ and referer_path =~ /^\/web/
|
198
|
+
self.search_engine = 'Ask'
|
199
|
+
self.search_query = params['q'].try(:first)
|
200
|
+
elsif referer_host == 'search.aol.com' and referer_path == '/aol/search'
|
201
|
+
self.search_engine = 'AOL'
|
202
|
+
self.search_query = params['q'].try(:first)
|
203
|
+
elsif referer_host =~ /metacrawler\.com$/ and referer_path =~ /search\/web/
|
204
|
+
self.search_engine = 'MetaCrawler'
|
205
|
+
self.search_query = params['q'].try(:first)
|
206
|
+
elsif referer_host =~ /dogpile\.com/ and referer_path =~ /dogpile\/ws\/results\/Web\//
|
207
|
+
self.search_engine = 'Dogpile'
|
208
|
+
void, self.search_query = referer_path.match(/ws\/results\/Web\/([^\/]*)\//).to_a
|
209
|
+
self.search_query = CGI::unescape(self.search_query).gsub('!FE', '.')
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Parse the params to fill param_id and format attributes
|
215
|
+
def params=(params)
|
216
|
+
self.param_id = params[:id]
|
217
|
+
self.format = params[:format]
|
218
|
+
end
|
219
|
+
|
220
|
+
# Init the corrosponding Gricer::Session (called before create)
|
221
|
+
#
|
222
|
+
# @return [Gricer::Session]
|
223
|
+
def init_session
|
224
|
+
if session
|
225
|
+
if session.updated_at < Time.now - ::Gricer.config.max_session_duration
|
226
|
+
self.session = Session.create previous_session: session, ip_address: @ip_address, agent: agent, requested_locale: @request_locale
|
227
|
+
else
|
228
|
+
self.session.touch
|
229
|
+
end
|
230
|
+
else
|
231
|
+
self.is_first_in_session = true
|
232
|
+
self.session = Session.create ip_address: @ip_address, agent: agent, requested_locale: @request_locale
|
233
|
+
self.session.touch
|
234
|
+
end
|
235
|
+
|
236
|
+
session
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,433 @@
|
|
1
|
+
module Gricer
|
2
|
+
# ActiveRecord Model for Session Statistics
|
3
|
+
# @attr [Gricer::Session] previous_session
|
4
|
+
# The current value of the associated previous session.
|
5
|
+
#
|
6
|
+
# @attr [Gricer::Agent] agent
|
7
|
+
# The current value of the associated agent.
|
8
|
+
#
|
9
|
+
# @attr [String] ip_address_hash
|
10
|
+
# The current value of the ip address in an anonyminized hash
|
11
|
+
#
|
12
|
+
# @attr [String] domain
|
13
|
+
# The current value of the domain (only major info) from which the session was requested.
|
14
|
+
#
|
15
|
+
# @attr [String] country
|
16
|
+
# The current value of the country from which the session was requested.
|
17
|
+
#
|
18
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
19
|
+
#
|
20
|
+
# @attr [String] region
|
21
|
+
# The current value of the region from which the session was requested.
|
22
|
+
#
|
23
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
24
|
+
#
|
25
|
+
# @attr [String] city
|
26
|
+
# The current value of the city from which the session was requested.
|
27
|
+
#
|
28
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
29
|
+
#
|
30
|
+
# @attr [String] postal_code
|
31
|
+
# The current value of the region from which the session was requested.
|
32
|
+
#
|
33
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
34
|
+
#
|
35
|
+
# @attr [Float] longitude
|
36
|
+
# The current value of the longitude of the city/region from which the session was requested.
|
37
|
+
#
|
38
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
39
|
+
#
|
40
|
+
# @attr [Float] latitude
|
41
|
+
# The current value of the latitude of the city/region from which the session was requested.
|
42
|
+
#
|
43
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
44
|
+
#
|
45
|
+
# @attr [Boolean] javascript
|
46
|
+
# The current value of the javascript capability of the requesting agent.
|
47
|
+
#
|
48
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
49
|
+
#
|
50
|
+
# @attr [Boolean] java
|
51
|
+
# The current value of the java capability of the requesting agent.
|
52
|
+
#
|
53
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
54
|
+
#
|
55
|
+
# @attr [String] flash_version
|
56
|
+
# The current value of the version of flash installed on the requesting agent.
|
57
|
+
#
|
58
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
59
|
+
#
|
60
|
+
# @attr [String] flash_major_version
|
61
|
+
# The current value of the major version of flash installed on the requesting agent.
|
62
|
+
#
|
63
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
64
|
+
#
|
65
|
+
# @attr [String] silverlight_version
|
66
|
+
# The current value of the version of silverlight installed on the requesting agent.
|
67
|
+
#
|
68
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
69
|
+
#
|
70
|
+
# @attr [String] silverlight_major_version
|
71
|
+
# The current value of the major version of silverlight installed on the requesting agent.
|
72
|
+
#
|
73
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
74
|
+
#
|
75
|
+
# @attr [Integer] screen_width
|
76
|
+
# The current value of the width in pixels of the screen the requesting agent's window is on.
|
77
|
+
#
|
78
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
79
|
+
#
|
80
|
+
# @attr [Integer] screen_height
|
81
|
+
# The current value of the height in pixels of the screen the requesting agent's window is on.
|
82
|
+
#
|
83
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
84
|
+
#
|
85
|
+
# @attr [Integer] screen_depth
|
86
|
+
# The current value of the depth in bits of the screen the requesting agent's window is on.
|
87
|
+
#
|
88
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
89
|
+
#
|
90
|
+
# @attr [String] requested_locale_major
|
91
|
+
# The current value of the locale requested (major locale only)
|
92
|
+
#
|
93
|
+
# @attr [String] requested_locale_minor
|
94
|
+
# The current value of the locale requested (major locale only)
|
95
|
+
#
|
96
|
+
# @attr [String] requested_locale
|
97
|
+
# The current value of the locale requested
|
98
|
+
#
|
99
|
+
class Session < ::ActiveRecord::Base
|
100
|
+
set_table_name "#{::Gricer::config.table_name_prefix}sessions"
|
101
|
+
include ActiveModel::Statistics
|
102
|
+
|
103
|
+
has_many :requests, class_name: 'Gricer::Request', foreign_key: :session_id, order: 'created_at ASC'
|
104
|
+
belongs_to :agent, class_name: 'Gricer::Agent', foreign_key: :agent_id, counter_cache: true
|
105
|
+
belongs_to :previous_session, class_name: 'Gricer::Session', foreign_key: :previous_session_id
|
106
|
+
|
107
|
+
# Filter out anything that is not a Browser or MobileBrowser
|
108
|
+
# @return [ActiveRecord::Relation]
|
109
|
+
def self.browsers
|
110
|
+
self.includes("agent")
|
111
|
+
.where("\"#{Agent.table_name}\".\"agent_class_id\" IN (?)", [0x1000, 0x2000])
|
112
|
+
end
|
113
|
+
|
114
|
+
# Filter out only bounce sessions (sessions with just one request)
|
115
|
+
# @return [ActiveRecord::Relation]
|
116
|
+
def self.bounce_sessions
|
117
|
+
self.where("\"#{self.table_name}\".\"requests_count\" = ?", 1)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Filter out only new visits (which does not have a previous_session)
|
121
|
+
# @return [ActiveRecord::Relation]
|
122
|
+
def self.new_visits
|
123
|
+
where("\"#{self.table_name}\".\"previous_session_id\" IS NULL")
|
124
|
+
end
|
125
|
+
|
126
|
+
# This is just a list of two-part domain endings.
|
127
|
+
# It is used to get the domain from the request.
|
128
|
+
# return [Array]
|
129
|
+
def two_part_domain_endings
|
130
|
+
[
|
131
|
+
'com.ac','edu.ac','gov.ac','net.ac','mil.ac',
|
132
|
+
'org.ac','com.ae','net.ae','org.ae','gov.ae','ac.ae',
|
133
|
+
'co.ae','sch.ae','pro.ae','com.ai','org.ai','edu.ai',
|
134
|
+
'gov.ai','com.ar','net.ar','org.ar','gov.ar','mil.ar',
|
135
|
+
'edu.ar','int.ar','co.at','ac.at','or.at','gv.at','priv.at',
|
136
|
+
'com.au','gov.au','org.au','edu.au','id.au','oz.au',
|
137
|
+
'info.au','net.au','asn.au','csiro.au','telememo.au',
|
138
|
+
'conf.au','otc.au','com.az','net.az','org.az','com.bb',
|
139
|
+
'net.bb','org.bb','ac.be','belgie.be','dns.be','fgov.be',
|
140
|
+
'com.bh','gov.bh','net.bh','edu.bh','org.bh','com.bm',
|
141
|
+
'edu.bm','gov.bm','org.bm','net.bm','adm.br','adv.br',
|
142
|
+
'agr.br','am.br','arq.br','art.br','ato.br','bio.br',
|
143
|
+
'bmd.br','cim.br','cng.br','cnt.br','com.br','coop.br',
|
144
|
+
'ecn.br','edu.br','eng.br','esp.br','etc.br','eti.br',
|
145
|
+
'far.br','fm.br','fnd.br','fot.br','fst.br','g12.br',
|
146
|
+
'ggf.br','gov.br','imb.br','ind.br','inf.br','jor.br',
|
147
|
+
'lel.br','mat.br','med.br','mil.br','mus.br','net.br',
|
148
|
+
'nom.br','not.br','ntr.br','odo.br','org.br','ppg.br',
|
149
|
+
'pro.br','psc.br','psi.br','qsl.br','rec.br','slg.br',
|
150
|
+
'srv.br','tmp.br','trd.br','tur.br','tv.br','vet.br',
|
151
|
+
'zlg.br','com.bs','net.bs','org.bs','ab.ca','bc.ca',
|
152
|
+
'mb.ca','nb.ca','nf.ca','nl.ca','ns.ca','nt.ca','nu.ca',
|
153
|
+
'on.ca','pe.ca','qc.ca','sk.ca','yk.ca','gc.ca','co.ck',
|
154
|
+
'net.ck','org.ck','edu.ck','gov.ck','com.cn','edu.cn',
|
155
|
+
'gov.cn','net.cn','org.cn','ac.cn','ah.cn','bj.cn','cq.cn',
|
156
|
+
'gd.cn','gs.cn','gx.cn','gz.cn','hb.cn','he.cn','hi.cn',
|
157
|
+
'hk.cn','hl.cn','hn.cn','jl.cn','js.cn','ln.cn','mo.cn',
|
158
|
+
'nm.cn','nx.cn','qh.cn','sc.cn','sn.cn','sh.cn','sx.cn',
|
159
|
+
'tj.cn','tw.cn','xj.cn','xz.cn','yn.cn','zj.cn','arts.co',
|
160
|
+
'com.co','edu.co','firm.co','gov.co','info.co','int.co',
|
161
|
+
'nom.co','mil.co','org.co','rec.co','store.co','web.co',
|
162
|
+
'ac.cr','co.cr','ed.cr','fi.cr','go.cr','or.cr','sa.cr',
|
163
|
+
'com.cu','net.cu','org.cu','ac.cy','com.cy','gov.cy',
|
164
|
+
'net.cy','org.cy','co.dk','art.do','com.do','edu.do',
|
165
|
+
'gov.do','gob.do','org.do','mil.do','net.do','sld.do',
|
166
|
+
'web.do','com.dz','org.dz','net.dz','gov.dz','edu.dz',
|
167
|
+
'ass.dz','pol.dz','art.dz','com.ec','k12.ec','edu.ec',
|
168
|
+
'fin.ec','med.ec','gov.ec','mil.ec','org.ec','net.ec',
|
169
|
+
'com.ee','pri.ee','fie.ee','org.ee','med.ee','com.eg',
|
170
|
+
'edu.eg','eun.eg','gov.eg','net.eg','org.eg','sci.eg',
|
171
|
+
'com.er','net.er','org.er','edu.er','mil.er','gov.er',
|
172
|
+
'ind.er','com.es','org.es','gob.es','edu.es','nom.es',
|
173
|
+
'com.et','gov.et','org.et','edu.et','net.et','biz.et',
|
174
|
+
'name.et','info.et','ac.fj','com.fj','gov.fj','id.fj',
|
175
|
+
'org.fj','school.fj','com.fk','ac.fk','gov.fk','net.fk',
|
176
|
+
'nom.fk','org.fk','asso.fr','nom.fr','barreau.fr',
|
177
|
+
'com.fr','prd.fr','presse.fr','tm.fr','aeroport.fr',
|
178
|
+
'assedic.fr','avocat.fr','avoues.fr','cci.fr',
|
179
|
+
'chambagri.fr','chirurgiens-dentistes.fr',
|
180
|
+
'experts-comptables.fr','geometre-expert.fr',
|
181
|
+
'gouv.fr','greta.fr','huissier-justice.fr','medecin.fr',
|
182
|
+
'notaires.fr','pharmacien.fr','port.fr','veterinaire.fr',
|
183
|
+
'com.ge','edu.ge','gov.ge','mil.ge','net.ge','org.ge',
|
184
|
+
'pvt.ge','co.gg','org.gg','sch.gg','ac.gg','gov.gg',
|
185
|
+
'ltd.gg','ind.gg','net.gg','alderney.gg','guernsey.gg',
|
186
|
+
'sark.gg','com.gt','edu.gt','net.gt','gob.gt','org.gt',
|
187
|
+
'mil.gt','ind.gt','com.gu','edu.gu','net.gu','org.gu',
|
188
|
+
'gov.gu','mil.gu','com.hk','net.hk','org.hk','idv.hk',
|
189
|
+
'gov.hk','edu.hk','co.hu','2000.hu','erotika.hu',
|
190
|
+
'jogasz.hu','sex.hu','video.hu','info.hu','agrar.hu',
|
191
|
+
'film.hu','konyvelo.hu','shop.hu','org.hu','bolt.hu',
|
192
|
+
'forum.hu','lakas.hu','suli.hu','priv.hu','casino.hu',
|
193
|
+
'games.hu','media.hu','szex.hu','sport.hu','city.hu',
|
194
|
+
'hotel.hu','news.hu','tozsde.hu','tm.hu','erotica.hu',
|
195
|
+
'ingatlan.hu','reklam.hu','utazas.hu','ac.id','co.id',
|
196
|
+
'go.id','mil.id','net.id','or.id','co.il','net.il',
|
197
|
+
'org.il','ac.il','gov.il','k12.il','muni.il','idf.il',
|
198
|
+
'co.im','net.im','org.im','ac.im','lkd.co.im','gov.im',
|
199
|
+
'nic.im','plc.co.im','co.in','net.in','ac.in','ernet.in',
|
200
|
+
'gov.in','nic.in','res.in','gen.in','firm.in','mil.in',
|
201
|
+
'org.in','ind.in','ac.je','co.je','net.je','org.je',
|
202
|
+
'gov.je','ind.je','jersey.je','ltd.je','sch.je','com.jo',
|
203
|
+
'org.jo','net.jo','gov.jo','edu.jo','mil.jo','ad.jp',
|
204
|
+
'ac.jp','co.jp','go.jp','or.jp','ne.jp','gr.jp','ed.jp',
|
205
|
+
'lg.jp','net.jp','org.jp','gov.jp','hokkaido.jp',
|
206
|
+
'aomori.jp','iwate.jp','miyagi.jp','akita.jp',
|
207
|
+
'yamagata.jp','fukushima.jp','ibaraki.jp','tochigi.jp',
|
208
|
+
'gunma.jp','saitama.jp','chiba.jp','tokyo.jp',
|
209
|
+
'kanagawa.jp','niigata.jp','toyama.jp','ishikawa.jp',
|
210
|
+
'fukui.jp','yamanashi.jp','nagano.jp','gifu.jp',
|
211
|
+
'shizuoka.jp','aichi.jp','mie.jp','shiga.jp','kyoto.jp',
|
212
|
+
'osaka.jp','hyogo.jp','nara.jp','wakayama.jp','tottori.jp',
|
213
|
+
'shimane.jp','okayama.jp','hiroshima.jp','yamaguchi.jp',
|
214
|
+
'tokushima.jp','kagawa.jp','ehime.jp','kochi.jp',
|
215
|
+
'fukuoka.jp','saga.jp','nagasaki.jp','kumamoto.jp',
|
216
|
+
'oita.jp','miyazaki.jp','kagoshima.jp','okinawa.jp',
|
217
|
+
'sapporo.jp','sendai.jp','yokohama.jp','kawasaki.jp',
|
218
|
+
'nagoya.jp','kobe.jp','kitakyushu.jp','utsunomiya.jp',
|
219
|
+
'kanazawa.jp','takamatsu.jp','matsuyama.jp','com.kh',
|
220
|
+
'net.kh','org.kh','per.kh','edu.kh','gov.kh','mil.kh',
|
221
|
+
'ac.kr','co.kr','go.kr','ne.kr','or.kr','pe.kr','re.kr',
|
222
|
+
'seoul.kr','kyonggi.kr','com.kw','net.kw','org.kw',
|
223
|
+
'edu.kw','gov.kw','com.la','net.la','org.la','com.lb',
|
224
|
+
'org.lb','net.lb','edu.lb','gov.lb','mil.lb','com.lc',
|
225
|
+
'edu.lc','gov.lc','net.lc','org.lc','com.lv','net.lv',
|
226
|
+
'org.lv','edu.lv','gov.lv','mil.lv','id.lv','asn.lv',
|
227
|
+
'conf.lv','com.ly','net.ly','org.ly','co.ma','net.ma',
|
228
|
+
'org.ma','press.ma','ac.ma','com.mk','com.mm','net.mm',
|
229
|
+
'org.mm','edu.mm','gov.mm','com.mo','net.mo','org.mo',
|
230
|
+
'edu.mo','gov.mo','com.mt','net.mt','org.mt','edu.mt',
|
231
|
+
'tm.mt','uu.mt','com.mx','net.mx','org.mx','com.my',
|
232
|
+
'org.my','gov.my','edu.my','net.my','com.na','org.na',
|
233
|
+
'net.na','alt.na','edu.na','cul.na','unam.na','telecom.na',
|
234
|
+
'com.nc','net.nc','org.nc','ac.ng','edu.ng','sch.ng',
|
235
|
+
'com.ng','gov.ng','org.ng','net.ng','gob.ni','com.ni',
|
236
|
+
'net.ni','edu.ni','nom.ni','org.ni','com.np','net.np',
|
237
|
+
'org.np','gov.np','edu.np','ac.nz','co.nz','cri.nz',
|
238
|
+
'gen.nz','geek.nz','govt.nz','iwi.nz','maori.nz','mil.nz',
|
239
|
+
'net.nz','org.nz','school.nz','com.om','co.om','edu.om',
|
240
|
+
'ac.om','gov.om','net.om','org.om','mod.om','museum.om',
|
241
|
+
'biz.om','pro.om','med.om','com.pa','net.pa','org.pa',
|
242
|
+
'edu.pa','ac.pa','gob.pa','sld.pa','edu.pe','gob.pe',
|
243
|
+
'nom.pe','mil.pe','org.pe','com.pe','net.pe','com.pg',
|
244
|
+
'net.pg','ac.pg','com.ph','net.ph','org.ph','mil.ph',
|
245
|
+
'ngo.ph','aid.pl','agro.pl','atm.pl','auto.pl','biz.pl',
|
246
|
+
'com.pl','edu.pl','gmina.pl','gsm.pl','info.pl','mail.pl',
|
247
|
+
'miasta.pl','media.pl','mil.pl','net.pl',
|
248
|
+
'nieruchomosci.pl','nom.pl','org.pl','pc.pl','powiat.pl',
|
249
|
+
'priv.pl','realestate.pl','rel.pl','sex.pl','shop.pl',
|
250
|
+
'sklep.pl','sos.pl','szkola.pl','targi.pl','tm.pl',
|
251
|
+
'tourism.pl','travel.pl','turystyka.pl','com.pk','net.pk',
|
252
|
+
'edu.pk','org.pk','fam.pk','biz.pk','web.pk','gov.pk',
|
253
|
+
'gob.pk','gok.pk','gon.pk','gop.pk','gos.pk','edu.ps',
|
254
|
+
'gov.ps','plo.ps','sec.ps','com.py','net.py','org.py',
|
255
|
+
'edu.py','com.qa','net.qa','org.qa','edu.qa','gov.qa',
|
256
|
+
'asso.re','com.re','nom.re','com.ro','org.ro','tm.ro',
|
257
|
+
'nt.ro','nom.ro','info.ro','rec.ro','arts.ro','firm.ro',
|
258
|
+
'store.ro','www.ro','com.ru','net.ru','org.ru','gov.ru',
|
259
|
+
'pp.ru','com.sa','edu.sa','sch.sa','med.sa','gov.sa',
|
260
|
+
'net.sa','org.sa','pub.sa','com.sb','net.sb','org.sb',
|
261
|
+
'edu.sb','gov.sb','com.sd','net.sd','org.sd','edu.sd',
|
262
|
+
'sch.sd','med.sd','gov.sd','tm.se','press.se','parti.se',
|
263
|
+
'brand.se','fh.se','fhsk.se','fhv.se','komforb.se',
|
264
|
+
'kommunalforbund.se','komvux.se','lanarb.se','lanbib.se',
|
265
|
+
'naturbruksgymn.se','sshn.se','org.se','pp.se','com.sg',
|
266
|
+
'net.sg','org.sg','edu.sg','gov.sg','per.sg','com.sh',
|
267
|
+
'net.sh','org.sh','edu.sh','gov.sh','mil.sh','gov.st',
|
268
|
+
'saotome.st','principe.st','consulado.st','embaixada.st',
|
269
|
+
'org.st','edu.st','net.st','com.st','store.st','mil.st',
|
270
|
+
'co.st','com.sv','org.sv','edu.sv','gob.sv','red.sv',
|
271
|
+
'com.sy','net.sy','org.sy','gov.sy','ac.th','co.th',
|
272
|
+
'go.th','net.th','or.th','com.tn','net.tn','org.tn',
|
273
|
+
'edunet.tn','gov.tn','ens.tn','fin.tn','nat.tn','ind.tn',
|
274
|
+
'info.tn','intl.tn','rnrt.tn','rnu.tn','rns.tn',
|
275
|
+
'tourism.tn','com.tr','net.tr','org.tr','edu.tr','gov.tr',
|
276
|
+
'mil.tr','bbs.tr','k12.tr','gen.tr','co.tt','com.tt',
|
277
|
+
'org.tt','net.tt','biz.tt','info.tt','pro.tt','name.tt',
|
278
|
+
'gov.tt','edu.tt','nic.tt','us.tt','uk.tt','ca.tt','eu.tt',
|
279
|
+
'es.tt','fr.tt','it.tt','se.tt','dk.tt','be.tt','de.tt',
|
280
|
+
'at.tt','au.tt','co.tv','com.tw','net.tw','org.tw',
|
281
|
+
'edu.tw','idv.tw','gove.tw','com.ua','net.ua','org.ua',
|
282
|
+
'edu.ua','gov.ua','ac.ug','co.ug','or.ug','go.ug','co.uk',
|
283
|
+
'me.uk','org.uk','edu.uk','ltd.uk','plc.uk','net.uk',
|
284
|
+
'sch.uk','nic.uk','ac.uk','gov.uk','nhs.uk','police.uk',
|
285
|
+
'mod.uk','dni.us','fed.us','com.uy','edu.uy','net.uy',
|
286
|
+
'org.uy','gub.uy','mil.uy','com.ve','net.ve','org.ve',
|
287
|
+
'co.ve','edu.ve','gov.ve','mil.ve','arts.ve','bib.ve',
|
288
|
+
'firm.ve','info.ve','int.ve','nom.ve','rec.ve','store.ve',
|
289
|
+
'tec.ve','web.ve','co.vi','net.vi','org.vi','com.vn',
|
290
|
+
'biz.vn','edu.vn','gov.vn','net.vn','org.vn','int.vn',
|
291
|
+
'ac.vn','pro.vn','info.vn','health.vn','name.vn','com.vu',
|
292
|
+
'edu.vu','net.vu','org.vu','de.vu','ch.vu','fr.vu',
|
293
|
+
'com.ws','net.ws','org.ws','gov.ws','edu.ws','ac.yu',
|
294
|
+
'co.yu','edu.yu','org.yu','com.ye','net.ye','org.ye',
|
295
|
+
'gov.ye','edu.ye','mil.ye','ac.za','alt.za','bourse.za',
|
296
|
+
'city.za','co.za','edu.za','gov.za','law.za','mil.za',
|
297
|
+
'net.za','ngo.za','nom.za','org.za','school.za','tm.za',
|
298
|
+
'web.za','co.zw','ac.zw','org.zw','gov.zw','eu.org',
|
299
|
+
'au.com','br.com','cn.com','de.com','de.net','eu.com',
|
300
|
+
'gb.com','gb.net','hu.com','no.com','qc.com','ru.com',
|
301
|
+
'sa.com','se.com','uk.com','uk.net','us.com','uy.com',
|
302
|
+
'za.com','dk.org','tel.no','fax.nr','mob.nr','mobil.nr',
|
303
|
+
'mobile.nr','tel.nr','tlf.nr','e164.arpa'
|
304
|
+
]
|
305
|
+
end
|
306
|
+
|
307
|
+
# Parse the requesting IP address and fill corrosponding attributes
|
308
|
+
# @param ip [String] An IP address (IPv4 only at the moment)
|
309
|
+
def ip_address=(ip)
|
310
|
+
require 'digest/sha1'
|
311
|
+
require 'resolv'
|
312
|
+
|
313
|
+
logger.debug("IP: #{ip}")
|
314
|
+
|
315
|
+
unless ip.blank?
|
316
|
+
self.ip_address_hash = Digest::SHA1.hexdigest(ip)
|
317
|
+
|
318
|
+
# IP
|
319
|
+
begin
|
320
|
+
domain_parts = Resolv.getname(ip).split('.')
|
321
|
+
|
322
|
+
self.domain = "#{domain_parts[-1]}"
|
323
|
+
|
324
|
+
self.domain = "#{domain_parts[-2]}.#{domain}" if domain_parts[-2]
|
325
|
+
|
326
|
+
if two_part_domain_endings.include? self.domain
|
327
|
+
self.domain = "#{domain_parts[-3]}.#{self.domain}"
|
328
|
+
end
|
329
|
+
rescue
|
330
|
+
ip_parts = ip.split('.')
|
331
|
+
self.domain = "#{ip_parts[0]}.#{ip_parts[1]}.x.x"
|
332
|
+
end
|
333
|
+
|
334
|
+
# GeoIP
|
335
|
+
if ::Gricer.config.geoip_db
|
336
|
+
if Rails.env.development?
|
337
|
+
geoip = {:country_code=>"DE", :country_code3=>"DEU", :country_name=>"Germany", :latitude=>51.0, :longitude=>9.0}
|
338
|
+
else
|
339
|
+
geoip = ::Gricer.config.geoip_db.look_up(ip)
|
340
|
+
end
|
341
|
+
|
342
|
+
|
343
|
+
if geoip
|
344
|
+
self.country = geoip[:country_code].try(:downcase)
|
345
|
+
self.region = geoip[:region].try(:downcase)
|
346
|
+
self.city = geoip[:city]
|
347
|
+
self.postal_code = geoip[:postal_code]
|
348
|
+
self.longitude = geoip[:longitude]
|
349
|
+
self.latitude = geoip[:latitude]
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def requested_locale=(locale)
|
356
|
+
self.requested_locale_major, self.requested_locale_minor = locale.try(:downcase).try(:split, '-')
|
357
|
+
end
|
358
|
+
|
359
|
+
def requested_locale
|
360
|
+
if requested_locale_minor
|
361
|
+
"#{requested_locale_major}-#{requested_locale_minor}"
|
362
|
+
else
|
363
|
+
requested_locale_major
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
def silverlight_version=(version)
|
368
|
+
self[:silverlight_version] = version
|
369
|
+
self.silverlight_major_version = silverlight_version.match(/^([0-9]*\.[0-9]*)/).to_a.last if silverlight_version
|
370
|
+
end
|
371
|
+
|
372
|
+
def flash_version=(version)
|
373
|
+
self[:flash_version] = version
|
374
|
+
self.flash_major_version = flash_version.match(/^([0-9]*\.[0-9]*)/).to_a.last if flash_version
|
375
|
+
end
|
376
|
+
|
377
|
+
# Get the bounce rate
|
378
|
+
#
|
379
|
+
# This is the rate of sessions with one request to sessions with multiple requests.
|
380
|
+
# @return [Float]
|
381
|
+
def self.bounce_rate
|
382
|
+
if (c = self.count) > 0
|
383
|
+
self.bounce_sessions.count / c.to_f
|
384
|
+
else
|
385
|
+
0
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
# Get the average count of requests per session.
|
390
|
+
#
|
391
|
+
# @return [Float]
|
392
|
+
def self.requests_per_session
|
393
|
+
if (c = self.count) > 0
|
394
|
+
self.sum(:requests_count) / c.to_f
|
395
|
+
else
|
396
|
+
0
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
# Get the average duration of sessions in seconds.
|
401
|
+
#
|
402
|
+
# @return [Float]
|
403
|
+
def self.avg_duration
|
404
|
+
if (c = self.count) > 0
|
405
|
+
logger.debug ActiveRecord::Base.connection.class
|
406
|
+
|
407
|
+
if ActiveRecord::Base.connection.class.to_s == 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter'
|
408
|
+
self.sum("date_part('epoch', \"#{self.table_name}\".\"updated_at\") - date_part('epoch', \"#{self.table_name}\".\"created_at\")").to_f / c.to_f
|
409
|
+
else
|
410
|
+
self.sum("strftime('%s', \"#{self.table_name}\".\"updated_at\") - strftime('%s', \"#{self.table_name}\".\"created_at\")") / c.to_f
|
411
|
+
end
|
412
|
+
else
|
413
|
+
0
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
# Get the duration of the current session instance
|
418
|
+
def duration
|
419
|
+
updated_at - created_at
|
420
|
+
end
|
421
|
+
|
422
|
+
# Get the new visitor rate
|
423
|
+
#
|
424
|
+
# This is the rate of new sessions to all sessions
|
425
|
+
def self.new_visitors
|
426
|
+
if (c = self.count) > 0
|
427
|
+
self.new_visits.count / c.to_f
|
428
|
+
else
|
429
|
+
0
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|