Files

165 lines
6.9 KiB
Python
Raw Permalink Normal View History

2026-05-11 03:27:21 +03:30
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from rest_framework.exceptions import NotFound
from rest_framework import serializers, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from farm_hub.models import FarmHub
from .enums import FARMER_TAG_ITEMS
from .models import FarmerCalendarEvent
from .serializers import (
FarmerCalendarEventResponseSerializer,
FarmerCalendarEventWriteSerializer,
FarmerCalendarListQuerySerializer,
FarmerCalendarTagIdSerializer,
)
class FarmerCalendarBaseView(APIView):
permission_classes = [IsAuthenticated]
@staticmethod
def error_response(message, details=None, code="EVENT_VALIDATION_ERROR", status_code=status.HTTP_400_BAD_REQUEST):
payload = {
"code": code,
"message": message,
}
if details is not None:
payload["details"] = details
return Response(payload, status=status_code)
def handle_exception(self, exc):
if isinstance(exc, serializers.ValidationError):
details = exc.detail
message = "Invalid event payload"
if isinstance(details, dict):
first_value = next(iter(details.values()), None)
if isinstance(first_value, list) and first_value:
message = str(first_value[0])
elif first_value:
message = str(first_value)
elif isinstance(details, list) and details:
message = str(details[0])
return self.error_response(message=message, details=details)
if isinstance(exc, NotFound):
return self.error_response(
message=str(exc.detail),
code="EVENT_NOT_FOUND",
status_code=status.HTTP_404_NOT_FOUND,
)
return super().handle_exception(exc)
def _get_user_farms(self, request):
return FarmHub.objects.filter(owner=request.user).order_by("id")
def _resolve_farm(self, request, farm_uuid=None, required=False):
farms = self._get_user_farms(request)
if farm_uuid:
try:
return farms.get(farm_uuid=farm_uuid)
except FarmHub.DoesNotExist as exc:
raise serializers.ValidationError({"farm_uuid": ["Farm not found."]}) from exc
if required:
farm_count = farms.count()
if farm_count == 1:
return farms.first()
if farm_count == 0:
raise serializers.ValidationError({"farm_uuid": ["No farm found for this user."]})
raise serializers.ValidationError({"farm_uuid": ["farm_uuid is required when multiple farms exist."]})
return None
def _get_event(self, request, event_id):
queryset = FarmerCalendarEvent.objects.select_related("farm").prefetch_related("tags")
try:
return queryset.get(uuid=event_id, farm__owner=request.user)
except FarmerCalendarEvent.DoesNotExist as exc:
raise NotFound("Event not found.") from exc
class EventListCreateView(FarmerCalendarBaseView):
@extend_schema(
tags=["Farmer Calendar"],
parameters=[
OpenApiParameter(name="start", type=OpenApiTypes.DATETIME, location=OpenApiParameter.QUERY, required=False),
OpenApiParameter(name="end", type=OpenApiTypes.DATETIME, location=OpenApiParameter.QUERY, required=False),
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=False),
],
)
def get(self, request):
query_serializer = FarmerCalendarListQuerySerializer(data=request.query_params)
query_serializer.is_valid(raise_exception=True)
queryset = FarmerCalendarEvent.objects.filter(farm__owner=request.user).prefetch_related("tags")
farm = self._resolve_farm(request, query_serializer.validated_data.get("farm_uuid"), required=False)
if farm is not None:
queryset = queryset.filter(farm=farm)
start = query_serializer.validated_data.get("start")
end = query_serializer.validated_data.get("end")
if start:
queryset = queryset.filter(end__gte=start)
if end:
queryset = queryset.filter(start__lte=end)
events = queryset.order_by("start", "created_at")
data = FarmerCalendarEventResponseSerializer(events, many=True).data
return Response({"events": data, "meta": {"total": len(data)}}, status=status.HTTP_200_OK)
@extend_schema(tags=["Farmer Calendar"])
def post(self, request):
serializer = FarmerCalendarEventWriteSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
farm = self._resolve_farm(request, serializer.validated_data.get("farm_uuid"), required=True)
event = serializer.save(farm=farm)
data = FarmerCalendarEventResponseSerializer(event).data
return Response({"event": data}, status=status.HTTP_201_CREATED)
class EventTagListView(FarmerCalendarBaseView):
@extend_schema(
tags=["Farmer Calendar"],
parameters=[
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=False),
],
)
def get(self, request):
self._resolve_farm(request, request.query_params.get("farm_uuid"), required=False)
data = FarmerCalendarTagIdSerializer(FARMER_TAG_ITEMS, many=True).data
return Response({"tags": data, "meta": {"total": len(data)}}, status=status.HTTP_200_OK)
class EventDetailView(FarmerCalendarBaseView):
@extend_schema(tags=["Farmer Calendar"])
def get(self, request, event_id):
event = self._get_event(request, event_id)
data = FarmerCalendarEventResponseSerializer(event).data
return Response({"event": data}, status=status.HTTP_200_OK)
@extend_schema(tags=["Farmer Calendar"])
def put(self, request, event_id):
event = self._get_event(request, event_id)
serializer = FarmerCalendarEventWriteSerializer(event, data=request.data)
serializer.is_valid(raise_exception=True)
requested_farm_uuid = serializer.validated_data.get("farm_uuid")
if requested_farm_uuid and str(event.farm.farm_uuid) != str(requested_farm_uuid):
return self.error_response(
message="farm_uuid cannot change an existing event",
details={"farm_uuid": ["farm_uuid cannot change an existing event"]},
)
event = serializer.save()
data = FarmerCalendarEventResponseSerializer(event).data
return Response({"event": data}, status=status.HTTP_200_OK)
@extend_schema(tags=["Farmer Calendar"])
def delete(self, request, event_id):
event = self._get_event(request, event_id)
event.delete()
return Response({"success": True}, status=status.HTTP_200_OK)