1
from datetime import datetime, timedelta
6
from django.conf import settings
7
from django.contrib.auth.models import AnonymousUser
8
from django.core.cache import cache
9
from django.core.urlresolvers import reverse, NoReverseMatch
10
from django.db.utils import DatabaseError
11
from django.http import Http404
13
from tracking import utils
14
from tracking.models import Visitor, UntrackedUserAgent, BannedIP
16
title_re = re.compile('<title>(.*?)</title>')
17
log = logging.getLogger('tracking.middleware')
20
class VisitorTrackingMiddleware(object):
21
"""Keeps track of your active users. Anytime a visitor accesses a valid
22
URL, their unique record will be updated with the page they're on and the
23
last time they requested a page.
25
Records are considered to be unique when the session key and IP
26
address are unique together. Sometimes the same user used to have
27
two different records, so I added a check to see if the session key
28
had changed for the same IP and user agent in the last 5 minutes
34
"""Returns a list of URL prefixes that we should not track."""
36
if not hasattr(self, '_prefixes'):
37
self._prefixes = getattr(settings, 'NO_TRACKING_PREFIXES', [])
39
if not getattr(settings, '_FREEZE_TRACKING_PREFIXES', False):
40
for name in ('MEDIA_URL', 'STATIC_URL'):
41
url = getattr(settings, name)
42
if url and url != '/':
43
self._prefixes.append(url)
46
# finally, don't track requests to the tracker update pages
47
self._prefixes.append(
48
reverse('tracking-refresh-active-users'))
49
except NoReverseMatch:
50
# django-tracking hasn't been included in the URLconf if we
51
# get here, which is not a bad thing
54
settings.NO_TRACKING_PREFIXES = self._prefixes
55
settings._FREEZE_TRACKING_PREFIXES = True
59
def process_request(self, request):
60
# don't process AJAX requests
64
# create some useful variables
65
ip_address = utils.get_ip(request)
66
user_agent = unicode(request.META.get(
67
'HTTP_USER_AGENT', '')[:255], errors='ignore')
69
# retrieve untracked user agents from cache
70
ua_key = '_tracking_untracked_uas'
71
untracked = cache.get(ua_key)
73
log.info('Updating untracked user agent cache')
74
untracked = UntrackedUserAgent.objects.all()
75
cache.set(ua_key, untracked, 3600)
77
# see if the user agent is not supposed to be tracked
79
# if the keyword is found in the user agent, stop tracking
80
if user_agent.find(ua.keyword) != -1:
81
log.debug('Not tracking UA "%s" because of keyword: %s' %
82
(user_agent, ua.keyword))
85
if hasattr(request, 'session') and request.session.session_key:
86
# use the current session key if we can
87
session_key = request.session.session_key
89
# otherwise just fake a session key
90
session_key = '%s:%s' % (ip_address, user_agent)
91
session_key = session_key[:40]
93
# ensure that the request.path does not begin with any of the prefixes
94
for prefix in self.prefixes:
95
if request.path.startswith(prefix):
96
log.debug('Not tracking request to: %s' % request.path)
99
# if we get here, the URL needs to be tracked
100
# determine what time it is
104
'session_key': session_key,
105
'ip_address': ip_address
108
# for some reason, Visitor.objects.get_or_create was not working here
110
visitor = Visitor.objects.get(**attrs)
111
except Visitor.DoesNotExist:
112
# see if there's a visitor with the same IP and user agent
113
# within the last 5 minutes
114
cutoff = now - timedelta(minutes=5)
115
visitors = Visitor.objects.filter(
116
ip_address=ip_address,
117
user_agent=user_agent,
118
last_update__gte=cutoff
122
visitor = visitors[0]
123
visitor.session_key = session_key
124
log.debug('Using existing visitor for IP %s / UA %s: %s' %
125
(ip_address, user_agent, visitor.id))
127
# it's probably safe to assume that the visitor is brand new
128
visitor = Visitor(**attrs)
129
log.debug('Created a new visitor: %s' % attrs)
133
# determine whether or not the user is logged in
135
if isinstance(user, AnonymousUser):
138
# update the tracking information
140
visitor.user_agent = user_agent
142
# if the visitor record is new, or the visitor hasn't been here for
143
# at least an hour, update their referrer URL
144
one_hour_ago = now - timedelta(hours=1)
145
if not visitor.last_update or visitor.last_update <= one_hour_ago:
146
visitor.referrer = utils.u_clean(
147
request.META.get('HTTP_REFERER', 'unknown')[:255])
149
# reset the number of pages they've been to
150
visitor.page_views = 0
151
visitor.session_start = now
153
visitor.url = request.path
154
visitor.page_views += 1
155
visitor.last_update = now
158
except DatabaseError:
159
log.error('There was a problem saving visitor information:\n%s\n\n%s' % (
160
traceback.format_exc(), locals()))
163
class VisitorCleanUpMiddleware:
164
"""Clean up old visitor tracking records in the database."""
166
def process_request(self, request):
167
timeout = utils.get_cleanup_timeout()
169
if str(timeout).isdigit():
170
log.debug('Cleaning up visitors older than %s hours' % timeout)
171
timeout = datetime.now() - timedelta(hours=int(timeout))
172
Visitor.objects.filter(last_update__lte=timeout).delete()
175
class BannedIPMiddleware:
176
"""Raises an Http404 error for any page request from a banned IP. IP
177
addresses may be added to the list of banned IPs via the Django admin.
179
The banned users do not actually receive the 404 error--instead they get
180
an "Internal Server Error", effectively eliminating any access to the site.
184
def process_request(self, request):
185
key = '_tracking_banned_ips'
188
# compile a list of all banned IP addresses
189
log.info('Updating banned IPs cache')
190
ips = [b.ip_address for b in BannedIP.objects.all()]
191
cache.set(key, ips, 3600)
193
# check to see if the current user's IP address is in that list
194
if utils.get_ip(request) in ips: