From 82af34c2e45e5436fecd5fb13c2eef9744c633bc Mon Sep 17 00:00:00 2001 From: saani Date: Thu, 4 Dec 2025 10:57:19 +0000 Subject: [PATCH] feat: add start and end meeting endpoints for scheduled appointments --- booking_system/views.py | 23 +++++++++++++++++ meetings/urls.py | 7 ++++- meetings/views.py | 57 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/booking_system/views.py b/booking_system/views.py index 8ec9df0..3edbb47 100644 --- a/booking_system/views.py +++ b/booking_system/views.py @@ -360,6 +360,29 @@ def api_root(request, format=None): "Clears scheduled datetime if any" ] }, + "start_meeting": { + "description": "Start the Jitsi meeting for a scheduled appointment", + "url": request.build_absolute_uri("/api/meetings/appointments//start/"), + "methods": ["POST"], + "authentication": "Required", + "prerequisites": "Appointment must be in 'scheduled' status", + "side_effects": [ + "Updates meeting status to 'active'", + "Allows participants to join the meeting" + ] + }, + "end_meeting": { + "description": "End the Jitsi meeting for a scheduled appointment", + "url": request.build_absolute_uri("/api/meetings/appointments//end/"), + "methods": ["POST"], + "authentication": "Required", + "prerequisites": "Appointment must be in 'scheduled' or 'active' status", + "side_effects": [ + "Updates meeting status to 'completed'", + "Clears Jitsi meeting information", + "Sends completion email to user" + ] + }, "appointment_stats": { "description": "Get appointment statistics and analytics with availability metrics (Admin only)", diff --git a/meetings/urls.py b/meetings/urls.py index a258020..cdd9a0a 100644 --- a/meetings/urls.py +++ b/meetings/urls.py @@ -19,7 +19,9 @@ from .views import ( UpcomingMeetingsView, MeetingAnalyticsView, BulkMeetingActionsView, - availability_overview + availability_overview, + EndMeetingView, + StartMeetingView ) urlpatterns = [ @@ -96,6 +98,9 @@ urlpatterns = [ # Meeting Status & Info path('meetings//status/', MeetingActionView.as_view(), {'get_status': True}, name='meeting-status'), path('meetings//info/', JoinMeetingView.as_view(), {'info_only': True}, name='meeting-info'), + + path('meetings//end/', EndMeetingView.as_view(), name='end-meeting-simple'), + path('meetings//start/', StartMeetingView.as_view(), name='start-meeting-simple'), # Meeting Webhook/Notification endpoints (for Jitsi callbacks) path('meetings/webhook/jitsi/', MeetingActionView.as_view(), {'webhook': True}, name='jitsi-webhook'), diff --git a/meetings/views.py b/meetings/views.py index 3045bd6..d9d2896 100644 --- a/meetings/views.py +++ b/meetings/views.py @@ -407,6 +407,63 @@ class MatchingAvailabilityView(generics.GenericAPIView): ) +class StartMeetingView(generics.GenericAPIView): + permission_classes = [IsAuthenticated] + serializer_class = MeetingActionSerializer + queryset = AppointmentRequest.objects.all() + lookup_field = 'pk' + def post(self, request, pk): + appointment = self.get_object() + + if not request.user.is_staff: + return Response( + {'error': 'Only staff members can start meetings'}, + status=status.HTTP_403_FORBIDDEN + ) + + if appointment.status != 'scheduled': + return Response( + {'error': 'Only scheduled appointments can be started'}, + status=status.HTTP_400_BAD_REQUEST + ) + + appointment.start_meeting() + + return Response({ + 'appointment_id': str(appointment.id), + 'message': 'Meeting started successfully', + 'meeting_started_at': appointment.meeting_started_at, + }) + +class EndMeetingView(generics.GenericAPIView): + permission_classes = [IsAuthenticated] + serializer_class = MeetingActionSerializer + queryset = AppointmentRequest.objects.all() + lookup_field = 'pk' + + def post(self, request, pk): + appointment = self.get_object() + + if not request.user.is_staff: + return Response( + {'error': 'Only staff members can end meetings'}, + status=status.HTTP_403_FORBIDDEN + ) + + if appointment.status != 'scheduled': + return Response( + {'error': 'Only scheduled appointments can be ended'}, + status=status.HTTP_400_BAD_REQUEST + ) + + appointment.end_meeting() + + return Response({ + 'appointment_id': str(appointment.id), + 'message': 'Meeting ended successfully', + 'meeting_ended_at': appointment.meeting_ended_at, + }) + class JoinMeetingView(generics.GenericAPIView): permission_classes = [IsAuthenticated] serializer_class = MeetingJoinSerializer -- 2.39.5