feat: add start and end meeting endpoints for scheduled appointments #56
@ -360,6 +360,29 @@ def api_root(request, format=None):
|
|||||||
"Clears scheduled datetime if any"
|
"Clears scheduled datetime if any"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"start_meeting": {
|
||||||
|
"description": "Start the Jitsi meeting for a scheduled appointment",
|
||||||
|
"url": request.build_absolute_uri("/api/meetings/appointments/<uuid:pk>/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/<uuid:pk>/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": {
|
"appointment_stats": {
|
||||||
"description": "Get appointment statistics and analytics with availability metrics (Admin only)",
|
"description": "Get appointment statistics and analytics with availability metrics (Admin only)",
|
||||||
|
|||||||
@ -19,7 +19,9 @@ from .views import (
|
|||||||
UpcomingMeetingsView,
|
UpcomingMeetingsView,
|
||||||
MeetingAnalyticsView,
|
MeetingAnalyticsView,
|
||||||
BulkMeetingActionsView,
|
BulkMeetingActionsView,
|
||||||
availability_overview
|
availability_overview,
|
||||||
|
EndMeetingView,
|
||||||
|
StartMeetingView
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@ -96,6 +98,9 @@ urlpatterns = [
|
|||||||
# Meeting Status & Info
|
# Meeting Status & Info
|
||||||
path('meetings/<uuid:pk>/status/', MeetingActionView.as_view(), {'get_status': True}, name='meeting-status'),
|
path('meetings/<uuid:pk>/status/', MeetingActionView.as_view(), {'get_status': True}, name='meeting-status'),
|
||||||
path('meetings/<uuid:pk>/info/', JoinMeetingView.as_view(), {'info_only': True}, name='meeting-info'),
|
path('meetings/<uuid:pk>/info/', JoinMeetingView.as_view(), {'info_only': True}, name='meeting-info'),
|
||||||
|
|
||||||
|
path('meetings/<uuid:pk>/end/', EndMeetingView.as_view(), name='end-meeting-simple'),
|
||||||
|
path('meetings/<uuid:pk>/start/', StartMeetingView.as_view(), name='start-meeting-simple'),
|
||||||
|
|
||||||
# Meeting Webhook/Notification endpoints (for Jitsi callbacks)
|
# Meeting Webhook/Notification endpoints (for Jitsi callbacks)
|
||||||
path('meetings/webhook/jitsi/', MeetingActionView.as_view(), {'webhook': True}, name='jitsi-webhook'),
|
path('meetings/webhook/jitsi/', MeetingActionView.as_view(), {'webhook': True}, name='jitsi-webhook'),
|
||||||
|
|||||||
@ -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):
|
class JoinMeetingView(generics.GenericAPIView):
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
serializer_class = MeetingJoinSerializer
|
serializer_class = MeetingJoinSerializer
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user