from django.db.models import Q from django.shortcuts import get_object_or_404 from rest_framework import generics, status, permissions from rest_framework.response import Response from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter, OpenApiTypes from apps.meetings.models import MeetingRequest, MeetingStatus from apps.meetings.serializers import ( MeetingListSerializer, MeetingDetailSerializer, MeetingCreateSerializer, MeetingUpdateSerializer, ) from apps.meetings.permissions import IsMeetingParticipantOrStaff, CanManageMeeting from apps.profiles.models import InstitutionMember @extend_schema_view( get=extend_schema( tags=['Meetings'], summary="List scheduled & pending meetings", description="List bilateral video meetings involving the authenticated user's affiliated institutions.", parameters=[ OpenApiParameter('status', OpenApiTypes.STR, description="Meeting status (pending, scheduled, completed, cancelled, declined)"), OpenApiParameter('institution_id', OpenApiTypes.INT, description="Filter meetings by participating institution ID"), OpenApiParameter('start_date', OpenApiTypes.DATE, description="Filter meetings from date (YYYY-MM-DD)"), OpenApiParameter('end_date', OpenApiTypes.DATE, description="Filter meetings to date (YYYY-MM-DD)"), OpenApiParameter('search', OpenApiTypes.STR, description="Search in title or agenda"), ] ), post=extend_schema( tags=['Meetings'], summary="Propose a new video meeting", description="Schedule/propose a bilateral meeting between institutions (requires institution admin/editor role).", request=MeetingCreateSerializer, responses={201: MeetingDetailSerializer} ) ) class MeetingListCreateView(generics.ListCreateAPIView): permission_classes = [permissions.IsAuthenticated] def get_serializer_class(self): if self.request.method == 'POST': return MeetingCreateSerializer return MeetingListSerializer def get_queryset(self): user = self.request.user if not user.is_authenticated: return MeetingRequest.objects.none() if user.is_superuser or getattr(user, 'user_type', None) in ['super_admin', 'regional_admin']: qs = MeetingRequest.objects.select_related('requester_institution', 'recipient_institution', 'created_by').all() else: user_inst_ids = InstitutionMember.objects.filter(user=user).values_list('institution_id', flat=True) qs = MeetingRequest.objects.select_related('requester_institution', 'recipient_institution', 'created_by').filter( Q(requester_institution_id__in=user_inst_ids) | Q(recipient_institution_id__in=user_inst_ids) | Q(created_by=user) ) params = self.request.query_params status_param = params.get('status') if status_param: qs = qs.filter(status=status_param) institution_id = params.get('institution_id') if institution_id and str(institution_id).isdigit(): inst_id = int(institution_id) qs = qs.filter(Q(requester_institution_id=inst_id) | Q(recipient_institution_id=inst_id)) start_date = params.get('start_date') if start_date: qs = qs.filter(meeting_date__gte=start_date) end_date = params.get('end_date') if end_date: qs = qs.filter(meeting_date__lte=end_date) search = params.get('search') if search: qs = qs.filter(Q(title__icontains=search) | Q(agenda__icontains=search)) return qs.distinct() def perform_create(self, serializer): return serializer.save() def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) meeting = self.perform_create(serializer) out_serializer = MeetingDetailSerializer(meeting, context={'request': request}) return Response(out_serializer.data, status=status.HTTP_201_CREATED) @extend_schema_view( get=extend_schema( tags=['Meetings'], summary="Retrieve meeting details", description="Get full meeting details including video link, agenda, and participants." ), patch=extend_schema( tags=['Meetings'], summary="Update or respond to meeting request", description="Accept, reschedule, decline (requires rejection_reason or admin_notes explanation), complete, or update meeting room URL and agenda notes.", request=MeetingUpdateSerializer, responses={200: MeetingDetailSerializer} ), delete=extend_schema( tags=['Meetings'], summary="Cancel / delete meeting", description="Cancel or delete a meeting request." ) ) class MeetingDetailView(generics.RetrieveUpdateDestroyAPIView): permission_classes = [IsMeetingParticipantOrStaff] lookup_field = 'pk' def get_queryset(self): return MeetingRequest.objects.select_related('requester_institution', 'recipient_institution', 'created_by').all() def get_serializer_class(self): if self.request.method in ['PUT', 'PATCH']: return MeetingUpdateSerializer return MeetingDetailSerializer def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', True) instance = self.get_object() # Check manage permissions checker = CanManageMeeting() if not checker.has_object_permission(request, self, instance): self.permission_denied(request, message="You do not have permission to manage this meeting.") serializer = MeetingUpdateSerializer(instance, data=request.data, partial=partial, context={'request': request}) serializer.is_valid(raise_exception=True) self.perform_update(serializer) out_serializer = MeetingDetailSerializer(instance, context={'request': request}) return Response(out_serializer.data) def destroy(self, request, *args, **kwargs): instance = self.get_object() checker = CanManageMeeting() if not checker.has_object_permission(request, self, instance): self.permission_denied(request, message="You do not have permission to cancel this meeting.") return super().destroy(request, *args, **kwargs)