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