import logging import re from rest_framework.mixins import CreateModelMixin from rest_framework.permissions import IsAuthenticated from rest_framework.authentication import TokenAuthentication from rest_framework.generics import GenericAPIView from rest_framework.response import Response from rest_framework import status from apps.account.models import LocationHistory from apps.account.serializers import LocationHistorySerializer from utils.ip_helper import get_client_ip logger = logging.getLogger(__name__) def detect_browser_from_user_agent(user_agent): if not user_agent: return None try: ua = user_agent.lower() patterns = [ (r'edg/', 'Edge'), (r'opr/', 'Opera'), (r'chrome/', 'Chrome'), (r'firefox/', 'Firefox'), (r'safari/', 'Safari'), ] for pattern, browser in patterns: if re.search(pattern, ua): return browser return 'Unknown' except Exception: return None from drf_spectacular.utils import extend_schema, OpenApiResponse from rest_framework import serializers class RegionInfoSerializer(serializers.Serializer): ip = serializers.CharField(allow_null=True) browser = serializers.CharField(allow_null=True) user_agent = serializers.CharField(allow_blank=True) class LocationHistoryView(GenericAPIView, CreateModelMixin): permission_classes = [IsAuthenticated] authentication_classes = [TokenAuthentication] serializer_class = LocationHistorySerializer @extend_schema( summary="Record location update", description="Records client coordinates and IP address for session security.", tags=['Location'], request=LocationHistorySerializer, responses={201: LocationHistorySerializer} ) def post(self, request, *args, **kwargs): ip = get_client_ip(request) data = request.data.copy() data['ip'] = ip serializer = self.get_serializer(data=data) if serializer.is_valid(): serializer.save(user=request.user) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def get_queryset(self): if getattr(self, 'swagger_fake_view', False) or not self.request.user.is_authenticated: return LocationHistory.objects.none() return LocationHistory.objects.filter(user=self.request.user) class RegionInfoView(GenericAPIView): """ Returns basic client region, browser, and network info """ serializer_class = RegionInfoSerializer @extend_schema( summary="Get client region info", description="Returns basic client region, browser, and network info.", tags=['Location'], responses={200: RegionInfoSerializer} ) def get(self, request, *args, **kwargs): user_agent = request.META.get('HTTP_USER_AGENT', '') client_ip = get_client_ip(request) browser = detect_browser_from_user_agent(user_agent) return Response({ 'ip': client_ip, 'browser': browser, 'user_agent': user_agent, })