from datetime import timedelta import os from django.utils import timezone from rest_framework import status, viewsets from rest_framework.exceptions import Throttled from rest_framework.permissions import AllowAny, IsAdminUser from rest_framework.response import Response from rest_framework.views import APIView from .models import AvailabilityRequest, ScheduleEntry from .notifications import send_ntfy_notification from .serializers import ( AvailabilityRequestAdminSerializer, AvailabilityRequestCreateSerializer, AvailabilityRequestPublicSerializer, AvailabilityResponseSerializer, ScheduleEntrySerializer, ) def client_ip(request): forwarded = request.META.get('HTTP_X_FORWARDED_FOR') return forwarded.split(',')[0].strip() if forwarded else request.META.get('REMOTE_ADDR') def filter_schedule(queryset, request): start = request.query_params.get('start') end = request.query_params.get('end') if start and end: queryset = queryset.filter(start_date__lte=end, end_date__gte=start) return queryset class PublicScheduleView(APIView): permission_classes = [AllowAny] def get(self, request): queryset = filter_schedule(ScheduleEntry.objects.all(), request) return Response(ScheduleEntrySerializer(queryset, many=True).data) class PublicAvailabilityRequestCreateView(APIView): permission_classes = [AllowAny] def post(self, request): ip = client_ip(request) if ip and AvailabilityRequest.objects.filter( requester_ip=ip, requested_at__gte=timezone.now() - timedelta(seconds=45), ).exists(): raise Throttled(detail="Une demande vient déjà d'être envoyée. Réessaie dans quelques secondes.") serializer = AvailabilityRequestCreateSerializer(data=request.data) serializer.is_valid(raise_exception=True) item = serializer.save(requester_ip=ip) public_site_url = os.getenv('PUBLIC_SITE_URL', '').rstrip('/') message = f'{item.guest_name} demande si tu es disponible maintenant.' if item.message: message += f'\n{item.message}' send_ntfy_notification( 'Nouvelle demande de disponibilité', message, f'{public_site_url}/requests' if public_site_url else None, ) return Response( AvailabilityRequestPublicSerializer(item).data, status=status.HTTP_201_CREATED, ) class PublicAvailabilityRequestDetailView(APIView): permission_classes = [AllowAny] def get(self, request, token): try: item = AvailabilityRequest.objects.get(public_token=token) except AvailabilityRequest.DoesNotExist: return Response({'detail': 'Demande introuvable.'}, status=status.HTTP_404_NOT_FOUND) return Response(AvailabilityRequestPublicSerializer(item).data) class AdminScheduleViewSet(viewsets.ModelViewSet): serializer_class = ScheduleEntrySerializer permission_classes = [IsAdminUser] def get_queryset(self): return filter_schedule(ScheduleEntry.objects.all(), self.request) class AdminAvailabilityRequestViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = AvailabilityRequestAdminSerializer permission_classes = [IsAdminUser] def get_queryset(self): queryset = AvailabilityRequest.objects.all() status_filter = self.request.query_params.get('status') if status_filter: queryset = queryset.filter(status=status_filter) return queryset def respond(self, request, pk=None): item = self.get_object() serializer = AvailabilityResponseSerializer(data=request.data) serializer.is_valid(raise_exception=True) new_status = serializer.validated_data['status'] duration = serializer.validated_data.get('duration_minutes') item.status = new_status item.duration_minutes = duration if new_status == 'accepted' else None item.available_until = ( timezone.now() + timedelta(minutes=duration) if new_status == 'accepted' and duration else None ) item.response_message = serializer.validated_data.get('response_message', '') item.responded_at = timezone.now() item.save() return Response(AvailabilityRequestAdminSerializer(item).data)