""" Analytics and tracking middleware for Django application. """ import pghistory from django.contrib.auth.models import AnonymousUser from django.core.handlers.wsgi import WSGIRequest from django.utils.deprecation import MiddlewareMixin from django.contrib.contenttypes.models import ContentType from django.views.generic.detail import DetailView from core.analytics import PageView class RequestContextProvider(pghistory.context): """Custom context provider for pghistory that extracts information from the request.""" def __call__(self, request: WSGIRequest) -> dict: return { "user": ( str(request.user) if request.user and not isinstance(request.user, AnonymousUser) else None ), "ip": request.META.get("REMOTE_ADDR"), "user_agent": request.META.get("HTTP_USER_AGENT"), "session_key": ( request.session.session_key if hasattr(request, "session") else None ), } # Initialize the context provider request_context = RequestContextProvider() class PgHistoryContextMiddleware: """ Middleware that ensures request object is available to pghistory context. """ def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) return response class PageViewMiddleware(MiddlewareMixin): """Middleware to track page views for DetailView-based pages.""" def process_view(self, request, view_func, view_args, view_kwargs): # Only track GET requests if request.method != "GET": return None # Get view class if it exists view_class = getattr(view_func, "view_class", None) if not view_class or not issubclass(view_class, DetailView): return None # Get the object if it's a detail view try: view_instance = view_class() view_instance.request = request view_instance.args = view_args view_instance.kwargs = view_kwargs obj = view_instance.get_object() except (AttributeError, Exception): return None # Record the page view try: PageView.objects.create( content_type=ContentType.objects.get_for_model(obj.__class__), object_id=obj.pk, ip_address=request.META.get("REMOTE_ADDR", ""), user_agent=request.META.get("HTTP_USER_AGENT", "")[:512], ) except Exception: # Fail silently to not interrupt the request pass return None