agdar/mdt/api_views.py
Marwan Alwali 2f1681b18c update
2025-11-11 13:44:48 +03:00

326 lines
12 KiB
Python

"""
Django REST Framework API views for MDT app.
"""
from rest_framework import viewsets, filters, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django_filters.rest_framework import DjangoFilterBackend
from django.db.models import Q, Count, Prefetch
from django.utils import timezone
from .models import (
MDTNote,
MDTContribution,
MDTApproval,
MDTMention,
MDTAttachment,
)
from .serializers import (
MDTNoteSerializer,
MDTNoteListSerializer,
MDTContributionSerializer,
MDTApprovalSerializer,
MDTMentionSerializer,
MDTAttachmentSerializer,
)
class MDTNoteViewSet(viewsets.ModelViewSet):
"""
API endpoint for MDT notes.
Provides CRUD operations and additional actions for multidisciplinary team notes.
"""
queryset = MDTNote.objects.all()
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['patient', 'status', 'initiated_by', 'tenant']
search_fields = ['title', 'purpose', 'summary', 'recommendations', 'patient__mrn',
'patient__first_name_en', 'patient__last_name_en']
ordering_fields = ['created_at', 'finalized_at']
ordering = ['-created_at']
def get_serializer_class(self):
"""Use lightweight serializer for list view."""
if self.action == 'list':
return MDTNoteListSerializer
return MDTNoteSerializer
def get_queryset(self):
"""Optimize queryset with prefetching."""
queryset = super().get_queryset()
if self.action == 'retrieve':
queryset = queryset.prefetch_related(
Prefetch('contributions', queryset=MDTContribution.objects.select_related('contributor', 'clinic')),
Prefetch('approvals', queryset=MDTApproval.objects.select_related('approver', 'clinic')),
Prefetch('attachments', queryset=MDTAttachment.objects.select_related('uploaded_by')),
)
return queryset.select_related('patient', 'initiated_by', 'tenant')
@action(detail=False, methods=['get'])
def my_notes(self, request):
"""Get MDT notes where user is a contributor."""
my_notes = self.get_queryset().filter(
contributors=request.user
).distinct()
page = self.paginate_queryset(my_notes)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(my_notes, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def pending_approval(self, request):
"""Get notes pending approval."""
pending_notes = self.get_queryset().filter(
status=MDTNote.Status.PENDING_APPROVAL
)
serializer = self.get_serializer(pending_notes, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def finalized(self, request):
"""Get finalized notes."""
finalized_notes = self.get_queryset().filter(
status=MDTNote.Status.FINALIZED
)
page = self.paginate_queryset(finalized_notes)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(finalized_notes, many=True)
return Response(serializer.data)
@action(detail=True, methods=['post'])
def finalize(self, request, pk=None):
"""Finalize an MDT note."""
mdt_note = self.get_object()
try:
mdt_note.finalize()
serializer = self.get_serializer(mdt_note)
return Response(serializer.data)
except ValueError as e:
return Response(
{'error': str(e)},
status=status.HTTP_400_BAD_REQUEST
)
@action(detail=True, methods=['post'])
def archive(self, request, pk=None):
"""Archive an MDT note."""
mdt_note = self.get_object()
if mdt_note.status != MDTNote.Status.FINALIZED:
return Response(
{'error': 'Only finalized notes can be archived'},
status=status.HTTP_400_BAD_REQUEST
)
mdt_note.status = MDTNote.Status.ARCHIVED
mdt_note.save()
serializer = self.get_serializer(mdt_note)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def statistics(self, request):
"""Get MDT note statistics."""
queryset = self.get_queryset()
stats = {
'total_notes': queryset.count(),
'by_status': dict(
queryset.values('status').annotate(count=Count('id')).values_list('status', 'count')
),
'draft_count': queryset.filter(status=MDTNote.Status.DRAFT).count(),
'pending_approval_count': queryset.filter(status=MDTNote.Status.PENDING_APPROVAL).count(),
'finalized_count': queryset.filter(status=MDTNote.Status.FINALIZED).count(),
'archived_count': queryset.filter(status=MDTNote.Status.ARCHIVED).count(),
'total_contributions': MDTContribution.objects.filter(mdt_note__in=queryset).count(),
'total_approvals': MDTApproval.objects.filter(mdt_note__in=queryset, approved=True).count(),
}
return Response(stats)
class MDTContributionViewSet(viewsets.ModelViewSet):
"""
API endpoint for MDT contributions.
"""
queryset = MDTContribution.objects.all()
serializer_class = MDTContributionSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['mdt_note', 'contributor', 'clinic', 'is_final']
search_fields = ['content']
ordering_fields = ['created_at', 'edited_at']
ordering = ['created_at']
def get_queryset(self):
"""Optimize queryset."""
return super().get_queryset().select_related('mdt_note', 'contributor', 'clinic')
@action(detail=False, methods=['get'])
def my_contributions(self, request):
"""Get contributions by current user."""
my_contributions = self.get_queryset().filter(contributor=request.user)
serializer = self.get_serializer(my_contributions, many=True)
return Response(serializer.data)
@action(detail=True, methods=['post'])
def mark_final(self, request, pk=None):
"""Mark contribution as final."""
contribution = self.get_object()
if contribution.contributor != request.user:
return Response(
{'error': 'Only the contributor can mark their contribution as final'},
status=status.HTTP_403_FORBIDDEN
)
contribution.is_final = True
contribution.save()
serializer = self.get_serializer(contribution)
return Response(serializer.data)
class MDTApprovalViewSet(viewsets.ModelViewSet):
"""
API endpoint for MDT approvals.
"""
queryset = MDTApproval.objects.all()
serializer_class = MDTApprovalSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
filterset_fields = ['mdt_note', 'approver', 'clinic', 'approved']
ordering_fields = ['approved_at', 'created_at']
ordering = ['-approved_at']
def get_queryset(self):
"""Optimize queryset."""
return super().get_queryset().select_related('mdt_note', 'approver', 'clinic')
@action(detail=True, methods=['post'])
def approve(self, request, pk=None):
"""Approve an MDT note."""
approval = self.get_object()
if approval.approver != request.user:
return Response(
{'error': 'Only the assigned approver can approve'},
status=status.HTTP_403_FORBIDDEN
)
comments = request.data.get('comments', '')
approval.approve(comments=comments)
serializer = self.get_serializer(approval)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def pending(self, request):
"""Get pending approvals for current user."""
pending_approvals = self.get_queryset().filter(
approver=request.user,
approved=False
)
serializer = self.get_serializer(pending_approvals, many=True)
return Response(serializer.data)
class MDTMentionViewSet(viewsets.ReadOnlyModelViewSet):
"""
API endpoint for MDT mentions (read-only).
"""
queryset = MDTMention.objects.all()
serializer_class = MDTMentionSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
filterset_fields = ['contribution', 'mentioned_user', 'viewed_at']
ordering_fields = ['created_at', 'viewed_at']
ordering = ['-created_at']
def get_queryset(self):
"""Optimize queryset."""
return super().get_queryset().select_related('contribution', 'mentioned_user')
@action(detail=False, methods=['get'])
def my_mentions(self, request):
"""Get mentions for current user."""
my_mentions = self.get_queryset().filter(mentioned_user=request.user)
serializer = self.get_serializer(my_mentions, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def unread(self, request):
"""Get unread mentions for current user."""
unread_mentions = self.get_queryset().filter(
mentioned_user=request.user,
viewed_at__isnull=True
)
serializer = self.get_serializer(unread_mentions, many=True)
return Response(serializer.data)
@action(detail=True, methods=['post'])
def mark_viewed(self, request, pk=None):
"""Mark mention as viewed."""
mention = self.get_object()
if mention.mentioned_user != request.user:
return Response(
{'error': 'Can only mark your own mentions as viewed'},
status=status.HTTP_403_FORBIDDEN
)
mention.mark_as_viewed()
serializer = self.get_serializer(mention)
return Response(serializer.data)
class MDTAttachmentViewSet(viewsets.ModelViewSet):
"""
API endpoint for MDT attachments.
"""
queryset = MDTAttachment.objects.all()
serializer_class = MDTAttachmentSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
filterset_fields = ['mdt_note', 'file_type', 'uploaded_by']
ordering_fields = ['created_at']
ordering = ['-created_at']
def get_queryset(self):
"""Optimize queryset."""
return super().get_queryset().select_related('mdt_note', 'uploaded_by')
@action(detail=False, methods=['get'])
def by_note(self, request):
"""Get attachments for a specific MDT note."""
mdt_note_id = request.query_params.get('mdt_note_id')
if not mdt_note_id:
return Response(
{'error': 'mdt_note_id parameter required'},
status=status.HTTP_400_BAD_REQUEST
)
attachments = self.get_queryset().filter(mdt_note_id=mdt_note_id)
serializer = self.get_serializer(attachments, many=True)
return Response(serializer.data)