Add public PageView tracking for portal analytics.
CI / test (pull_request) Successful in 13s

Closes #3 — record successful public GET hits, show last-30-day views and top pages on the analytics report, and keep portal/admin/API paths out of the counts.
This commit is contained in:
2026-08-20 05:32:09 -05:00
parent 30ce58e610
commit b054097f3d
9 changed files with 234 additions and 7 deletions
+45 -1
View File
@@ -1,10 +1,54 @@
import logging
from django.utils.crypto import get_random_string
from analytics.models import Attribution, UTMVisit
from analytics.models import Attribution, PageView, UTMVisit
logger = logging.getLogger(__name__)
CORRELATION_COOKIE = "ms_cid"
# Portal, auth, health, assets, and transactional public endpoints.
_SKIP_PREFIXES = (
"/portal/",
"/admin/",
"/accounts/",
"/api/",
"/healthz",
"/static/",
"/media/",
"/unsubscribe/",
)
_SKIP_PATHS = frozenset({"/robots.txt", "/sitemap.xml", "/favicon.ico"})
class PublicPageViewMiddleware:
"""Record successful GET hits on public marketing pages."""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if _should_record_page_view(request, response):
try:
PageView.objects.create(path=request.path[:512])
except Exception:
logger.exception("Failed to record page view for %s", request.path)
return response
def _should_record_page_view(request, response) -> bool:
if request.method != "GET":
return False
if getattr(response, "status_code", 0) != 200:
return False
path = request.path
if path in _SKIP_PATHS:
return False
return not any(path.startswith(prefix) for prefix in _SKIP_PREFIXES)
class UTMTrackingMiddleware:
"""Capture UTM params into UTMVisit and stash a correlation id cookie."""