269 lines
8.8 KiB
Python
269 lines
8.8 KiB
Python
"""
|
|
Survey analytics API views.
|
|
|
|
Provides endpoints for accessing survey engagement metrics:
|
|
- Engagement statistics
|
|
- Patient survey timelines
|
|
- Completion times
|
|
- Abandonment analysis
|
|
- Hourly activity
|
|
"""
|
|
from rest_framework import status, viewsets
|
|
from rest_framework.decorators import action
|
|
from rest_framework.response import Response
|
|
from rest_framework.permissions import IsAuthenticated
|
|
|
|
from .analytics import (
|
|
get_survey_engagement_stats,
|
|
get_patient_survey_timeline,
|
|
get_survey_completion_times,
|
|
get_survey_abandonment_analysis,
|
|
get_hourly_survey_activity,
|
|
)
|
|
from .models import SurveyInstance, SurveyTracking
|
|
from .serializers import SurveyInstanceSerializer, SurveyTrackingSerializer
|
|
|
|
|
|
class SurveyAnalyticsViewSet(viewsets.ViewSet):
|
|
"""
|
|
Survey analytics API.
|
|
|
|
Provides various metrics about survey engagement:
|
|
- Engagement rates (open, completion, abandonment)
|
|
- Time metrics (time to complete, time spent)
|
|
- Patient timelines
|
|
- Abandonment patterns
|
|
- Hourly activity
|
|
"""
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def engagement_stats(self, request):
|
|
"""
|
|
Get overall survey engagement statistics.
|
|
|
|
Query params:
|
|
- survey_template_id: Filter by survey template (optional)
|
|
- hospital_id: Filter by hospital (optional)
|
|
- days: Number of days to look back (default: 30)
|
|
"""
|
|
survey_template_id = request.query_params.get('survey_template_id')
|
|
hospital_id = request.query_params.get('hospital_id')
|
|
days = int(request.query_params.get('days', 30))
|
|
|
|
try:
|
|
stats = get_survey_engagement_stats(
|
|
survey_template_id=survey_template_id,
|
|
hospital_id=hospital_id,
|
|
days=days
|
|
)
|
|
return Response(stats)
|
|
except Exception as e:
|
|
return Response(
|
|
{'error': str(e)},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def patient_timeline(self, request):
|
|
"""
|
|
Get survey timeline for a specific patient.
|
|
|
|
Query params:
|
|
- patient_id: Required - Patient ID
|
|
"""
|
|
patient_id = request.query_params.get('patient_id')
|
|
|
|
if not patient_id:
|
|
return Response(
|
|
{'error': 'patient_id is required'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
try:
|
|
timeline = get_patient_survey_timeline(patient_id)
|
|
return Response({'timeline': timeline})
|
|
except Exception as e:
|
|
return Response(
|
|
{'error': str(e)},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def completion_times(self, request):
|
|
"""
|
|
Get individual survey completion times.
|
|
|
|
Query params:
|
|
- survey_template_id: Filter by survey template (optional)
|
|
- hospital_id: Filter by hospital (optional)
|
|
- days: Number of days to look back (default: 30)
|
|
"""
|
|
survey_template_id = request.query_params.get('survey_template_id')
|
|
hospital_id = request.query_params.get('hospital_id')
|
|
days = int(request.query_params.get('days', 30))
|
|
|
|
try:
|
|
completion_times = get_survey_completion_times(
|
|
survey_template_id=survey_template_id,
|
|
hospital_id=hospital_id,
|
|
days=days
|
|
)
|
|
return Response({'completion_times': completion_times})
|
|
except Exception as e:
|
|
return Response(
|
|
{'error': str(e)},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def abandonment_analysis(self, request):
|
|
"""
|
|
Analyze abandoned surveys to identify patterns.
|
|
|
|
Query params:
|
|
- survey_template_id: Filter by survey template (optional)
|
|
- hospital_id: Filter by hospital (optional)
|
|
- days: Number of days to look back (default: 30)
|
|
"""
|
|
survey_template_id = request.query_params.get('survey_template_id')
|
|
hospital_id = request.query_params.get('hospital_id')
|
|
days = int(request.query_params.get('days', 30))
|
|
|
|
try:
|
|
analysis = get_survey_abandonment_analysis(
|
|
survey_template_id=survey_template_id,
|
|
hospital_id=hospital_id,
|
|
days=days
|
|
)
|
|
return Response(analysis)
|
|
except Exception as e:
|
|
return Response(
|
|
{'error': str(e)},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def hourly_activity(self, request):
|
|
"""
|
|
Get survey activity by hour.
|
|
|
|
Query params:
|
|
- hospital_id: Filter by hospital (optional)
|
|
- days: Number of days to look back (default: 7)
|
|
"""
|
|
hospital_id = request.query_params.get('hospital_id')
|
|
days = int(request.query_params.get('days', 7))
|
|
|
|
try:
|
|
activity = get_hourly_survey_activity(
|
|
hospital_id=hospital_id,
|
|
days=days
|
|
)
|
|
return Response({'activity': activity})
|
|
except Exception as e:
|
|
return Response(
|
|
{'error': str(e)},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def summary_dashboard(self, request):
|
|
"""
|
|
Get a comprehensive summary dashboard with all key metrics.
|
|
|
|
Query params:
|
|
- hospital_id: Filter by hospital (optional)
|
|
- days: Number of days to look back (default: 30)
|
|
"""
|
|
hospital_id = request.query_params.get('hospital_id')
|
|
days = int(request.query_params.get('days', 30))
|
|
|
|
try:
|
|
# Get engagement stats
|
|
engagement = get_survey_engagement_stats(
|
|
hospital_id=hospital_id,
|
|
days=days
|
|
)
|
|
|
|
# Get abandonment analysis
|
|
abandonment = get_survey_abandonment_analysis(
|
|
hospital_id=hospital_id,
|
|
days=days
|
|
)
|
|
|
|
# Get top 10 fastest completions
|
|
fastest_completions = get_survey_completion_times(
|
|
hospital_id=hospital_id,
|
|
days=days
|
|
)[:10]
|
|
|
|
# Get top 10 slowest completions
|
|
slowest_completions = get_survey_completion_times(
|
|
hospital_id=hospital_id,
|
|
days=days
|
|
)[-10:] if len(get_survey_completion_times(hospital_id=hospital_id, days=days)) > 10 else []
|
|
|
|
return Response({
|
|
'engagement': engagement,
|
|
'abandonment': abandonment,
|
|
'fastest_completions': fastest_completions,
|
|
'slowest_completions': slowest_completions,
|
|
})
|
|
except Exception as e:
|
|
return Response(
|
|
{'error': str(e)},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
|
|
class SurveyTrackingViewSet(viewsets.ReadOnlyModelViewSet):
|
|
"""
|
|
Survey tracking events API.
|
|
|
|
View detailed tracking events for surveys:
|
|
- Page views
|
|
- Completions
|
|
- Abandonments
|
|
- Device/browser information
|
|
"""
|
|
queryset = SurveyTracking.objects.select_related(
|
|
'survey_instance',
|
|
'survey_instance__patient',
|
|
'survey_instance__survey_template'
|
|
).order_by('-created_at')
|
|
serializer_class = SurveyTrackingSerializer
|
|
permission_classes = [IsAuthenticated]
|
|
filterset_fields = ['survey_instance', 'event_type', 'device_type', 'browser']
|
|
search_fields = ['ip_address', 'user_agent']
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def by_survey(self, request):
|
|
"""
|
|
Get tracking events for a specific survey instance.
|
|
|
|
Query params:
|
|
- survey_instance_id: Required - SurveyInstance ID
|
|
"""
|
|
survey_instance_id = request.query_params.get('survey_instance_id')
|
|
|
|
if not survey_instance_id:
|
|
return Response(
|
|
{'error': 'survey_instance_id is required'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
try:
|
|
tracking_events = self.queryset.filter(
|
|
survey_instance_id=survey_instance_id
|
|
)
|
|
|
|
# Serialize and return
|
|
serializer = self.get_serializer(tracking_events, many=True)
|
|
return Response(serializer.data)
|
|
except Exception as e:
|
|
return Response(
|
|
{'error': str(e)},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|