You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

148 lines
6.4 KiB

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)