Skip to content

Commit

Permalink
Improved asset bed relations for camera preset (#2387)
Browse files Browse the repository at this point in the history
* Adds camera preset model

* Migration to backfill and soft delete duplicate asset bed records

* Delete assed bed records that has no asset class

* rebase migrations

* stash

* rebase migrations

* rebase migrations and fix issues

* fix accidentally creating preset in update preset

* remove boundary preset support

* optimize preset name valdiation check
---------

Co-authored-by: Aakash Singh <[email protected]>

* refactor viewsets

* make asset, bed, assetbed get_queryset reusable based on user

* prevent accidentally attempting to evaluate queryset early

* migration: skip purging data, handle exceptions; add tests

---------

Co-authored-by: Aakash Singh <[email protected]>
Co-authored-by: Mohammed Nihal <[email protected]>
  • Loading branch information
3 people authored Oct 18, 2024
1 parent 0fc5260 commit 14d3ef9
Show file tree
Hide file tree
Showing 13 changed files with 600 additions and 62 deletions.
13 changes: 8 additions & 5 deletions care/facility/api/serializers/bed.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,14 @@ def validate(self, attrs):
{"asset": "Should be in the same facility as the bed"}
)
if (
asset.asset_class == AssetClasses.HL7MONITOR.name
and AssetBed.objects.filter(
bed=bed, asset__asset_class=asset.asset_class
).exists()
):
asset.asset_class
in [
AssetClasses.HL7MONITOR.name,
AssetClasses.ONVIF.name,
]
) and AssetBed.objects.filter(
bed=bed, asset__asset_class=asset.asset_class
).exists():
raise ValidationError(
{
"asset": "Bed is already in use by another asset of the same class"
Expand Down
49 changes: 49 additions & 0 deletions care/facility/api/serializers/camera_preset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from care.facility.api.serializers.bed import AssetBedSerializer
from care.facility.models import CameraPreset
from care.users.api.serializers.user import UserBaseMinimumSerializer


class CameraPresetSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source="external_id", read_only=True)
created_by = UserBaseMinimumSerializer(read_only=True)
updated_by = UserBaseMinimumSerializer(read_only=True)
asset_bed = AssetBedSerializer(read_only=True)

class Meta:
model = CameraPreset
exclude = (
"external_id",
"deleted",
)
read_only_fields = (
"created_date",
"modified_date",
"is_migrated",
"created_by",
"updated_by",
)

def get_asset_bed_obj(self):
return (
self.instance.asset_bed if self.instance else self.context.get("asset_bed")
)

def validate_name(self, value):
if CameraPreset.objects.filter(
asset_bed__bed_id=self.get_asset_bed_obj().bed_id, name=value
).exists():
msg = "Name should be unique. Another preset related to this bed already uses the same name."
raise ValidationError(msg)
return value

def create(self, validated_data):
validated_data["created_by"] = self.context["request"].user
validated_data["asset_bed"] = self.get_asset_bed_obj()
return super().create(validated_data)

def update(self, instance, validated_data):
validated_data["updated_by"] = self.context["request"].user
return super().update(instance, validated_data)
17 changes: 2 additions & 15 deletions care/facility/api/viewsets/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
from care.utils.assetintegration.asset_classes import AssetClasses
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities
from care.utils.filters.choicefilter import CareChoiceFilter, inverse_choices
from care.utils.queryset.asset_bed import get_asset_queryset
from care.utils.queryset.asset_location import get_asset_location_queryset
from care.utils.queryset.facility import get_facility_queryset
from config.authentication import MiddlewareAuthentication
Expand Down Expand Up @@ -290,21 +291,7 @@ class AssetViewSet(
filterset_class = AssetFilter

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(current_location__facility__state=user.state)
elif user.user_type >= User.TYPE_VALUE_MAP["DistrictLabAdmin"]:
queryset = queryset.filter(
current_location__facility__district=user.district
)
else:
allowed_facilities = get_accessible_facilities(user)
queryset = queryset.filter(
current_location__facility__id__in=allowed_facilities
)
queryset = get_asset_queryset(user=self.request.user, queryset=self.queryset)
return queryset.annotate(
latest_status=Subquery(
AvailabilityRecord.objects.filter(
Expand Down
48 changes: 7 additions & 41 deletions care/facility/api/viewsets/bed.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from care.users.models import User
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities
from care.utils.filters.choicefilter import CareChoiceFilter, inverse_choices
from care.utils.queryset.asset_bed import get_asset_bed_queryset, get_bed_queryset

inverse_bed_type = inverse_choices(BedTypeChoices)

Expand Down Expand Up @@ -76,27 +77,14 @@ class BedViewSet(
filterset_class = BedFilter

def get_queryset(self):
user = self.request.user
queryset = self.queryset

queryset = queryset.annotate(
queryset = self.queryset.annotate(
is_occupied=Exists(
ConsultationBed.objects.filter(
bed__id=OuterRef("id"), end_date__isnull=True
)
)
)

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
return get_bed_queryset(user=self.request.user, queryset=queryset)

@transaction.atomic
def create(self, request, *args, **kwargs):
Expand Down Expand Up @@ -168,18 +156,7 @@ class AssetBedViewSet(
lookup_field = "external_id"

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(bed__facility__state=user.state)
elif user.user_type >= User.TYPE_VALUE_MAP["DistrictLabAdmin"]:
queryset = queryset.filter(bed__facility__district=user.district)
else:
allowed_facilities = get_accessible_facilities(user)
queryset = queryset.filter(bed__facility__id__in=allowed_facilities)
return queryset
return get_asset_bed_queryset(user=self.request.user, queryset=self.queryset)


class PatientAssetBedFilter(filters.FilterSet):
Expand Down Expand Up @@ -212,20 +189,9 @@ class PatientAssetBedViewSet(ListModelMixin, GenericViewSet):
]

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(bed__facility__state=user.state)
elif user.user_type >= User.TYPE_VALUE_MAP["DistrictLabAdmin"]:
queryset = queryset.filter(bed__facility__district=user.district)
else:
allowed_facilities = get_accessible_facilities(user)
queryset = queryset.filter(bed__facility__id__in=allowed_facilities)
return queryset.filter(
bed__facility__external_id=self.kwargs["facility_external_id"]
)
return get_asset_bed_queryset(
user=self.request.user, queryset=self.queryset
).filter(bed__facility__external_id=self.kwargs["facility_external_id"])


class ConsultationBedFilter(filters.FilterSet):
Expand Down
63 changes: 63 additions & 0 deletions care/facility/api/viewsets/camera_preset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from django.shortcuts import get_object_or_404
from rest_framework.exceptions import NotFound
from rest_framework.mixins import ListModelMixin
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import GenericViewSet, ModelViewSet

from care.facility.api.serializers.camera_preset import CameraPresetSerializer
from care.facility.models import CameraPreset
from care.utils.queryset.asset_bed import (
get_asset_bed_queryset,
get_asset_queryset,
get_bed_queryset,
)


class AssetBedCameraPresetViewSet(ModelViewSet):
serializer_class = CameraPresetSerializer
queryset = CameraPreset.objects.all().select_related(
"asset_bed", "created_by", "updated_by"
)
lookup_field = "external_id"
permission_classes = (IsAuthenticated,)

def get_asset_bed_obj(self):
queryset = get_asset_bed_queryset(self.request.user).filter(
external_id=self.kwargs["assetbed_external_id"]
)
return get_object_or_404(queryset)

def get_queryset(self):
return super().get_queryset().filter(asset_bed=self.get_asset_bed_obj())

def get_serializer_context(self):
context = super().get_serializer_context()
context["asset_bed"] = self.get_asset_bed_obj()
return context


class CameraPresetViewSet(GenericViewSet, ListModelMixin):
serializer_class = CameraPresetSerializer
queryset = CameraPreset.objects.all().select_related(
"asset_bed", "created_by", "updated_by"
)
lookup_field = "external_id"
permission_classes = (IsAuthenticated,)

def get_bed_obj(self, external_id: str):
queryset = get_bed_queryset(self.request.user).filter(external_id=external_id)
return get_object_or_404(queryset)

def get_asset_obj(self, external_id: str):
queryset = get_asset_queryset(self.request.user).filter(external_id=external_id)
return get_object_or_404(queryset)

def get_queryset(self):
queryset = super().get_queryset()
if asset_external_id := self.kwargs.get("asset_external_id"):
return queryset.filter(
asset_bed__asset=self.get_asset_obj(asset_external_id)
)
if bed_external_id := self.kwargs.get("bed_external_id"):
return queryset.filter(asset_bed__bed=self.get_bed_obj(bed_external_id))
raise NotFound
Loading

0 comments on commit 14d3ef9

Please sign in to comment.