Plain is headed towards 1.0! Subscribe for development updates →

 1import json
 2
 3from plain.runtime import settings
 4from plain.views import View
 5from plain.views.csrf import CsrfExemptViewMixin
 6
 7from .models import Pageview
 8
 9
10class TrackView(CsrfExemptViewMixin, View):
11    def post(self):
12        if getattr(self.request, "impersonator", None):
13            # Don't track page views if we're impersonating a user
14            return 200
15
16        try:
17            data = self.request.data
18        except json.JSONDecodeError:
19            return 400
20
21        try:
22            url = data["url"]
23            title = data["title"]
24            referrer = data["referrer"]
25            timestamp = data["timestamp"]
26        except KeyError:
27            return 400
28
29        if user := getattr(self.request, "user", None):
30            user_id = user.pk
31        else:
32            user_id = ""
33
34        if session := getattr(self.request, "session", None):
35            session_key = session.session_key or ""
36
37            if settings.PAGEVIEWS_ASSOCIATE_ANONYMOUS_SESSIONS:
38                if not user_id:
39                    if not session_key:
40                        # Make sure we have a key to use
41                        session.create()
42                        session_key = session.session_key
43
44                    # The user hasn't logged in yet but might later. When they do log in,
45                    # the session key itself will be cycled (session fixation attacks),
46                    # so we'll store the anonymous session id in the data which will be preserved
47                    # when the key cycles, then remove it immediately after.
48                    session["pageviews_anonymous_session_key"] = session_key
49                elif user_id and "pageviews_anonymous_session_key" in session:
50                    # Associate the previously anonymous pageviews with the user
51                    Pageview.objects.filter(
52                        user_id="",
53                        session_key=session["pageviews_anonymous_session_key"],
54                    ).update(user_id=user_id)
55
56                    # Remove it so we don't keep trying to associate it
57                    del session["pageviews_anonymous_session_key"]
58        else:
59            session_key = ""
60
61        Pageview.objects.create(
62            user_id=user_id,
63            session_key=session_key,
64            url=url,
65            title=title,
66            referrer=referrer,
67            timestamp=timestamp,
68        )
69
70        return 201