Skip to content

Commit

Permalink
Merge pull request #1825 from coronasafe/master
Browse files Browse the repository at this point in the history
Production Release | January Week 3
  • Loading branch information
gigincg authored Jan 16, 2024
2 parents 97f02a6 + 64485eb commit 5f3beec
Show file tree
Hide file tree
Showing 46 changed files with 837 additions and 676 deletions.
4 changes: 2 additions & 2 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ name = "pypi"
[packages]
argon2-cffi = "==23.1.0"
authlib = "==1.2.1"
boto3 = "==1.34.2"
boto3 = "==1.34.15"
celery = "==5.3.4"
django = "==4.2.8"
django-environ = "==0.11.2"
Expand Down Expand Up @@ -48,7 +48,7 @@ whitenoise = "==6.5.0"

[dev-packages]
black = "==23.9.1"
boto3-stubs = {extras = ["s3", "boto3"], version = "==1.34.2"}
boto3-stubs = {extras = ["s3", "boto3"], version = "==1.34.15"}
coverage = "==7.3.1"
debugpy = "==1.7.0"
django-coverage-plugin = "==3.1.0"
Expand Down
674 changes: 345 additions & 329 deletions Pipfile.lock

Large diffs are not rendered by default.

13 changes: 8 additions & 5 deletions care/facility/api/serializers/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
BLOOD_GROUP_CHOICES,
DISEASE_STATUS_CHOICES,
DiseaseStatusEnum,
NewDischargeReasonEnum,
)
from care.facility.models.patient_consultation import PatientConsultation
from care.facility.models.patient_external_test import PatientExternalTest
Expand Down Expand Up @@ -452,24 +453,26 @@ def validate_date_of_birth(self, value):
def create(self, validated_data):
raise NotImplementedError

def save(self, **kwargs):
self.instance.facility = self.validated_data["facility"]
def update(self, instance, validated_data):
instance.facility = validated_data["facility"]

with transaction.atomic():
consultation = PatientConsultation.objects.filter(
patient=self.instance, discharge_date__isnull=True
patient=instance, discharge_date__isnull=True
).first()

if consultation:
consultation.discharge_date = now()
consultation.discharge_reason = "REF"
consultation.new_discharge_reason = NewDischargeReasonEnum.REFERRED
consultation.current_bed = None
consultation.save()

ConsultationBed.objects.filter(
consultation=consultation, end_date__isnull=True
).update(end_date=now())
self.instance.save()

instance.save()
return instance


class PatientNotesSerializer(serializers.ModelSerializer):
Expand Down
16 changes: 8 additions & 8 deletions care/facility/api/serializers/patient_consultation.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
)
from care.facility.models.notification import Notification
from care.facility.models.patient_base import (
DISCHARGE_REASON_CHOICES,
SYMPTOM_CHOICES,
NewDischargeReasonEnum,
RouteToFacility,
SuggestionChoices,
)
Expand Down Expand Up @@ -111,8 +111,8 @@ class PatientConsultationSerializer(serializers.ModelSerializer):
queryset=User.objects.all(), required=False, allow_null=True
)

discharge_reason = serializers.ChoiceField(
choices=DISCHARGE_REASON_CHOICES, read_only=True, required=False
new_discharge_reason = serializers.ChoiceField(
choices=NewDischargeReasonEnum.choices, read_only=True, required=False
)
discharge_notes = serializers.CharField(read_only=True)

Expand Down Expand Up @@ -558,8 +558,8 @@ def validate(self, attrs):


class PatientConsultationDischargeSerializer(serializers.ModelSerializer):
discharge_reason = serializers.ChoiceField(
choices=DISCHARGE_REASON_CHOICES, required=True
new_discharge_reason = serializers.ChoiceField(
choices=NewDischargeReasonEnum.choices, required=True
)
discharge_notes = serializers.CharField(required=False, allow_blank=True)

Expand Down Expand Up @@ -596,7 +596,7 @@ def get_discharge_prn_prescription(self, consultation):
class Meta:
model = PatientConsultation
fields = (
"discharge_reason",
"new_discharge_reason",
"referred_to",
"referred_to_external",
"discharge_notes",
Expand All @@ -619,11 +619,11 @@ def validate(self, attrs):
],
}
)
if attrs.get("discharge_reason") != "EXP":
if attrs.get("new_discharge_reason") != NewDischargeReasonEnum.EXPIRED:
attrs.pop("death_datetime", None)
attrs.pop("death_confirmed_doctor", None)

if attrs.get("discharge_reason") == "EXP":
if attrs.get("new_discharge_reason") == NewDischargeReasonEnum.EXPIRED:
if not attrs.get("death_datetime"):
raise ValidationError({"death_datetime": "This field is required"})
if attrs.get("death_datetime") > now():
Expand Down
5 changes: 3 additions & 2 deletions care/facility/api/serializers/shifting.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
)
from care.facility.models.bed import ConsultationBed
from care.facility.models.notification import Notification
from care.facility.models.patient_base import NewDischargeReasonEnum
from care.facility.models.patient_consultation import PatientConsultation
from care.users.api.serializers.user import UserBaseMinimumSerializer
from care.utils.notification_handler import NotificationGenerator
Expand Down Expand Up @@ -70,9 +71,9 @@ def discharge_patient(patient: PatientRegistration):
PatientConsultation.objects.filter(patient=patient).order_by("-id").first()
)
if last_consultation:
reason = "REF"
reason = NewDischargeReasonEnum.REFERRED
notes = "Patient Shifted to another facility"
last_consultation.discharge_reason = reason
last_consultation.new_discharge_reason = reason
last_consultation.discharge_notes = notes
last_consultation.discharge_date = current_time
last_consultation.current_bed = None
Expand Down
9 changes: 7 additions & 2 deletions care/facility/api/viewsets/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ def operate_assets(self, request, *args, **kwargs):
return Response({"result": result}, status=status.HTTP_200_OK)

except ValidationError as e:
return Response({"message": e.detail}, status=status.HTTP_400_BAD_REQUEST)
return Response({"detail": e.detail}, status=status.HTTP_400_BAD_REQUEST)

except KeyError as e:
return Response(
Expand All @@ -347,7 +347,12 @@ def operate_assets(self, request, *args, **kwargs):
)

except APIException as e:
return Response(e.detail, e.status_code)
return Response(
{
"detail": f"Communication with the middleware failed.\nReceived status code: {e.status_code}"
},
status=status.HTTP_502_BAD_GATEWAY,
)

except Exception as e:
print(f"error: {e}")
Expand Down
28 changes: 14 additions & 14 deletions care/facility/api/viewsets/bed.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ class BedViewSet(
search_fields = ["name"]
filterset_class = BedFilter

def get_queryset(self):
user = self.request.user
queryset = self.queryset
if user.is_superuser:
pass
elif user.user_type >= User.TYPE_VALUE_MAP["StateLabAdmin"]:
queryset = queryset.filter(facility__state=user.state)
elif user.user_type >= User.TYPE_VALUE_MAP["DistrictLabAdmin"]:
queryset = queryset.filter(facility__district=user.district)
else:
allowed_facilities = get_accessible_facilities(user)
queryset = queryset.filter(facility__id__in=allowed_facilities)
return queryset

def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
Expand All @@ -83,20 +97,6 @@ def create(self, request, *args, **kwargs):
serializer.data, status=status.HTTP_201_CREATED, headers=headers
)

def get_queryset(self):
user = self.request.user
queryset = self.queryset
if user.is_superuser:
pass
elif user.user_type >= User.TYPE_VALUE_MAP["StateLabAdmin"]:
queryset = queryset.filter(facility__state=user.state)
elif user.user_type >= User.TYPE_VALUE_MAP["DistrictLabAdmin"]:
queryset = queryset.filter(facility__district=user.district)
else:
allowed_facilities = get_accessible_facilities(user)
queryset = queryset.filter(facility__id__in=allowed_facilities)
return queryset

def destroy(self, request, *args, **kwargs):
if request.user.user_type < User.TYPE_VALUE_MAP["DistrictLabAdmin"]:
raise PermissionDenied()
Expand Down
28 changes: 26 additions & 2 deletions care/facility/api/viewsets/file_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
RetrieveModelMixin,
UpdateModelMixin,
)
from rest_framework.permissions import IsAuthenticated
from rest_framework.permissions import BasePermission, IsAuthenticated
from rest_framework.viewsets import GenericViewSet

from care.facility.api.serializers.file_upload import (
Expand All @@ -18,13 +18,36 @@
check_permissions,
)
from care.facility.models.file_upload import FileUpload
from care.users.models import User


class FileUploadFilter(filters.FilterSet):
file_category = filters.CharFilter(field_name="file_category")
is_archived = filters.BooleanFilter(field_name="is_archived")


class FileUploadPermission(BasePermission):
def has_permission(self, request, view) -> bool:
if request.user.user_type in (
User.TYPE_VALUE_MAP["StaffReadOnly"],
User.TYPE_VALUE_MAP["Staff"],
):
if request.method == "GET":
return request.query_params.get("file_type") not in (
"PATIENT",
"CONSULTATION",
)
else:
return request.data.get("file_type") not in (
"PATIENT",
"CONSULTATION",
)
return True

def has_object_permission(self, request, view, obj) -> bool:
return self.has_permission(request, view)


class FileUploadViewSet(
CreateModelMixin,
RetrieveModelMixin,
Expand All @@ -36,7 +59,7 @@ class FileUploadViewSet(
queryset = (
FileUpload.objects.all().select_related("uploaded_by").order_by("-created_date")
)
permission_classes = [IsAuthenticated]
permission_classes = [IsAuthenticated, FileUploadPermission]
lookup_field = "external_id"
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = FileUploadFilter
Expand All @@ -54,6 +77,7 @@ def get_serializer_class(self):
def get_queryset(self):
if "file_type" not in self.request.GET:
raise ValidationError({"file_type": "file_type missing in request params"})

if "associating_id" not in self.request.GET:
raise ValidationError(
{"associating_id": "associating_id missing in request params"}
Expand Down
12 changes: 8 additions & 4 deletions care/facility/api/viewsets/hospital_doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from care.facility.api.viewsets import FacilityBaseViewset
from care.facility.models import Facility, HospitalDoctors
from care.users.models import User
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities


class HospitalDoctorViewSet(FacilityBaseViewset, ListModelMixin):
Expand All @@ -24,12 +25,15 @@ def get_queryset(self):
facility__external_id=self.kwargs.get("facility_external_id")
)
if user.is_superuser:
return queryset
pass
elif self.request.user.user_type >= User.TYPE_VALUE_MAP["StateLabAdmin"]:
return queryset.filter(facility__state=user.state)
queryset = queryset.filter(facility__state=user.state)
elif self.request.user.user_type >= User.TYPE_VALUE_MAP["DistrictLabAdmin"]:
return queryset.filter(facility__district=user.district)
return queryset.filter(facility__users__id__exact=user.id)
queryset = queryset.filter(facility__district=user.district)
else:
allowed_facilities = get_accessible_facilities(user)
queryset = queryset.filter(facility__id__in=allowed_facilities)
return queryset

def get_object(self):
return get_object_or_404(self.get_queryset(), area=self.kwargs.get("pk"))
Expand Down
5 changes: 4 additions & 1 deletion care/facility/api/viewsets/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from drf_spectacular.utils import extend_schema, inline_serializer
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.generics import get_object_or_404
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
Expand All @@ -13,6 +13,7 @@

from care.facility.api.serializers.notification import NotificationSerializer
from care.facility.models.notification import Notification
from care.users.models import User
from care.utils.filters.choicefilter import CareChoiceFilter, inverse_choices
from care.utils.notification_handler import NotificationGenerator
from care.utils.queryset.facility import get_facility_queryset
Expand Down Expand Up @@ -67,6 +68,8 @@ def public_key(self, request, *args, **kwargs):
@action(detail=False, methods=["POST"])
def notify(self, request, *args, **kwargs):
user = request.user
if user.user_type < User.TYPE_VALUE_MAP["Doctor"]:
raise PermissionDenied()
if "facility" not in request.data or request.data["facility"] == "":
raise ValidationError({"facility": "is required"})
if "message" not in request.data or request.data["message"] == "":
Expand Down
11 changes: 7 additions & 4 deletions care/facility/api/viewsets/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@
from care.facility.models.base import covert_choice_dict
from care.facility.models.bed import AssetBed
from care.facility.models.notification import Notification
from care.facility.models.patient_base import DISEASE_STATUS_DICT
from care.facility.models.patient_base import (
DISEASE_STATUS_DICT,
NewDischargeReasonEnum,
)
from care.users.models import User
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities
from care.utils.filters.choicefilter import CareChoiceFilter
Expand Down Expand Up @@ -177,9 +180,9 @@ def filter_by_bed_type(self, queryset, name, value):
field_name="last_consultation__current_bed__bed__bed_type",
choice_dict=REVERSE_BED_TYPES,
)
last_consultation_discharge_reason = filters.ChoiceFilter(
field_name="last_consultation__discharge_reason",
choices=DISCHARGE_REASON_CHOICES,
last_consultation__new_discharge_reason = filters.ChoiceFilter(
field_name="last_consultation__new_discharge_reason",
choices=NewDischargeReasonEnum.choices,
)
last_consultation_assigned_to = filters.NumberFilter(
field_name="last_consultation__assigned_to"
Expand Down
17 changes: 15 additions & 2 deletions care/facility/api/viewsets/patient_external_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
UpdateModelMixin,
)
from rest_framework.parsers import FormParser, JSONParser, MultiPartParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.permissions import BasePermission, IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet

Expand Down Expand Up @@ -64,6 +64,19 @@ class PatientExternalTestFilter(filters.FilterSet):
created_date = DateFromToRangeFilter(field_name="created_date")


class PatientExternalTestPermission(BasePermission):
def has_permission(self, request, view):
return request.user.user_type not in (
User.TYPE_VALUE_MAP["StaffReadOnly"],
User.TYPE_VALUE_MAP["Staff"],
User.TYPE_VALUE_MAP["NurseReadOnly"],
User.TYPE_VALUE_MAP["Nurse"],
)

def has_object_permission(self, request, view, obj):
return self.has_permission(request, view)


class PatientExternalTestViewSet(
RetrieveModelMixin,
ListModelMixin,
Expand All @@ -77,7 +90,7 @@ class PatientExternalTestViewSet(
.all()
.order_by("-id")
)
permission_classes = (IsAuthenticated,)
permission_classes = (IsAuthenticated, PatientExternalTestPermission)
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = PatientExternalTestFilter
parser_classes = (MultiPartParser, FormParser, JSONParser)
Expand Down
8 changes: 7 additions & 1 deletion care/facility/api/viewsets/patient_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from dry_rest_permissions.generics import DRYPermissionFiltersBase, DRYPermissions
from rest_framework import mixins, viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

Expand Down Expand Up @@ -117,6 +117,12 @@ def list(self, request, *args, **kwargs):
- district - District ID
- district_name - District name - case insensitive match
"""
if (
not self.kwargs.get("patient_external_id")
and request.user.user_type < User.TYPE_VALUE_MAP["Doctor"]
):
raise PermissionDenied()

if settings.CSV_REQUEST_PARAMETER in request.GET:
queryset = self.filter_queryset(self.get_queryset()).values(
*PatientSample.CSV_MAPPING.keys()
Expand Down
Loading

0 comments on commit 5f3beec

Please sign in to comment.