~widelands-dev/widelands-website/django_staticfiles

« back to all changes in this revision

Viewing changes to tracking/middleware.py

  • Committer: franku
  • Date: 2018-04-26 20:18:55 UTC
  • mfrom: (489.1.28 widelands)
  • Revision ID: somal@arcor.de-20180426201855-uwt3b8gptpav6wrm
updated code base to fit with django 1.11.12; replaced app tracking with a new middleware

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
from datetime import datetime, timedelta
2
 
import logging
3
 
import re
4
 
import traceback
5
 
 
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
12
 
 
13
 
from tracking import utils
14
 
from tracking.models import Visitor, UntrackedUserAgent, BannedIP
15
 
 
16
 
title_re = re.compile('<title>(.*?)</title>')
17
 
log = logging.getLogger('tracking.middleware')
18
 
 
19
 
 
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.
24
 
 
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
29
 
 
30
 
    """
31
 
 
32
 
    @property
33
 
    def prefixes(self):
34
 
        """Returns a list of URL prefixes that we should not track."""
35
 
 
36
 
        if not hasattr(self, '_prefixes'):
37
 
            self._prefixes = getattr(settings, 'NO_TRACKING_PREFIXES', [])
38
 
 
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)
44
 
 
45
 
                try:
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
52
 
                    pass
53
 
 
54
 
                settings.NO_TRACKING_PREFIXES = self._prefixes
55
 
                settings._FREEZE_TRACKING_PREFIXES = True
56
 
 
57
 
        return self._prefixes
58
 
 
59
 
    def process_request(self, request):
60
 
        # don't process AJAX requests
61
 
        if request.is_ajax():
62
 
            return
63
 
 
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')
68
 
 
69
 
        # retrieve untracked user agents from cache
70
 
        ua_key = '_tracking_untracked_uas'
71
 
        untracked = cache.get(ua_key)
72
 
        if untracked is None:
73
 
            log.info('Updating untracked user agent cache')
74
 
            untracked = UntrackedUserAgent.objects.all()
75
 
            cache.set(ua_key, untracked, 3600)
76
 
 
77
 
        # see if the user agent is not supposed to be tracked
78
 
        for ua in untracked:
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))
83
 
                return
84
 
 
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
88
 
        else:
89
 
            # otherwise just fake a session key
90
 
            session_key = '%s:%s' % (ip_address, user_agent)
91
 
            session_key = session_key[:40]
92
 
 
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)
97
 
                return
98
 
 
99
 
        # if we get here, the URL needs to be tracked
100
 
        # determine what time it is
101
 
        now = datetime.now()
102
 
 
103
 
        attrs = {
104
 
            'session_key': session_key,
105
 
            'ip_address': ip_address
106
 
        }
107
 
 
108
 
        # for some reason, Visitor.objects.get_or_create was not working here
109
 
        try:
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
119
 
            )
120
 
 
121
 
            if len(visitors):
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))
126
 
            else:
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)
130
 
        except:
131
 
            return
132
 
 
133
 
        # determine whether or not the user is logged in
134
 
        user = request.user
135
 
        if isinstance(user, AnonymousUser):
136
 
            user = None
137
 
 
138
 
        # update the tracking information
139
 
        visitor.user = user
140
 
        visitor.user_agent = user_agent
141
 
 
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])
148
 
 
149
 
            # reset the number of pages they've been to
150
 
            visitor.page_views = 0
151
 
            visitor.session_start = now
152
 
 
153
 
        visitor.url = request.path
154
 
        visitor.page_views += 1
155
 
        visitor.last_update = now
156
 
        try:
157
 
            visitor.save()
158
 
        except DatabaseError:
159
 
            log.error('There was a problem saving visitor information:\n%s\n\n%s' % (
160
 
                traceback.format_exc(), locals()))
161
 
 
162
 
 
163
 
class VisitorCleanUpMiddleware:
164
 
    """Clean up old visitor tracking records in the database."""
165
 
 
166
 
    def process_request(self, request):
167
 
        timeout = utils.get_cleanup_timeout()
168
 
 
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()
173
 
 
174
 
 
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.
178
 
 
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.
181
 
 
182
 
    """
183
 
 
184
 
    def process_request(self, request):
185
 
        key = '_tracking_banned_ips'
186
 
        ips = cache.get(key)
187
 
        if ips is None:
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)
192
 
 
193
 
        # check to see if the current user's IP address is in that list
194
 
        if utils.get_ip(request) in ips:
195
 
            raise Http404