Skip to content

Commit

Permalink
Allow Middleware to view users
Browse files Browse the repository at this point in the history
  • Loading branch information
vigneshhari committed Mar 22, 2022
1 parent 153ba14 commit 9e03d62
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 52 deletions.
14 changes: 9 additions & 5 deletions care/facility/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from djqscsv import render_to_csv_response

from care.facility.models.ambulance import Ambulance, AmbulanceDriver
from care.facility.models.bed import AssetBed
from care.facility.models.patient_sample import PatientSample
from care.facility.models.patient_tele_consultation import PatientTeleConsultation

Expand All @@ -22,12 +23,12 @@
Inventory,
InventoryItem,
InventoryLog,
PatientExternalTest,
PatientInvestigation,
PatientInvestigationGroup,
PatientRegistration,
Room,
StaffRoomAllocation,
PatientExternalTest,
PatientInvestigationGroup,
PatientInvestigation,
)


Expand All @@ -37,7 +38,7 @@ class BuildingAdmin(admin.ModelAdmin):


class DistrictFilter(SimpleListFilter):
"""DistrictFilter """
"""DistrictFilter"""

title = "District"
parameter_name = "district"
Expand Down Expand Up @@ -170,7 +171,9 @@ def export_as_csv(self, request, queryset):

queryset = FacilityUser.objects.all().values(*FacilityUser.CSV_MAPPING.keys())
return render_to_csv_response(
queryset, field_header_map=FacilityUser.CSV_MAPPING, field_serializer_map=FacilityUser.CSV_MAKE_PRETTY,
queryset,
field_header_map=FacilityUser.CSV_MAPPING,
field_serializer_map=FacilityUser.CSV_MAKE_PRETTY,
)

export_as_csv.short_description = "Export Selected"
Expand Down Expand Up @@ -205,3 +208,4 @@ class FacilityUserAdmin(DjangoQLSearchMixin, admin.ModelAdmin, ExportCsvMixin):
admin.site.register(PatientExternalTest, PatientExternalTestAdmin)
admin.site.register(PatientInvestigation, PatientTestAdmin)
admin.site.register(PatientInvestigationGroup, PatientTestGroupAdmin)
admin.site.register(AssetBed)
19 changes: 13 additions & 6 deletions care/facility/api/viewsets/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@
ShiftingRequest,
)
from care.facility.models.base import covert_choice_dict
from care.facility.models.bed import AssetBed
from care.facility.models.patient_base import DISEASE_STATUS_DICT
from care.facility.tasks.patient.discharge_report import generate_discharge_report
from care.users.models import User
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities
from care.utils.filters import CareChoiceFilter, MultiSelectFilter
from care.utils.queryset.patient import get_patient_queryset
from config.authentication import CustomBasicAuthentication, CustomJWTAuthentication, MiddlewareAuthentication

REVERSE_FACILITY_TYPES = covert_choice_dict(FACILITY_TYPES)

Expand Down Expand Up @@ -111,7 +113,13 @@ class PatientDRYFilter(DRYPermissionFiltersBase):
def filter_queryset(self, request, queryset, view):
if view.action == "list":
queryset = self.filter_list_queryset(request, queryset, view)

if request.user.asset:
return queryset.filter(
last_consultation__last_daily_round__bed_id__in=AssetBed.objects.filter(
asset=request.user.asset
).values("id"),
last_consultation__last_daily_round__bed__isnull=False,
)
if not request.user.is_superuser:
if request.user.user_type >= User.TYPE_VALUE_MAP["StateLabAdmin"]:
queryset = queryset.filter(facility__state=request.user.state)
Expand Down Expand Up @@ -145,6 +153,8 @@ class PatientViewSet(
mixins.UpdateModelMixin,
GenericViewSet,
):

authentication_classes = [CustomBasicAuthentication, CustomJWTAuthentication, MiddlewareAuthentication]
permission_classes = (IsAuthenticated, DRYPermissions)
lookup_field = "external_id"
queryset = PatientRegistration.objects.all().select_related(
Expand Down Expand Up @@ -242,12 +252,9 @@ def list(self, request, *args, **kwargs):
slice_obj = temp.form.cleaned_data.get(field)
if slice_obj:
if not slice_obj.start or not slice_obj.stop:
raise ValidationError(
{field: f"both starting and ending date must be provided for export"}
)
raise ValidationError({field: f"both starting and ending date must be provided for export"})
days_difference = (
temp.form.cleaned_data.get(field).stop
- temp.form.cleaned_data.get(field).start
temp.form.cleaned_data.get(field).stop - temp.form.cleaned_data.get(field).start
).days
if days_difference <= self.CSV_EXPORT_LIMIT:
within_limits = True
Expand Down
12 changes: 9 additions & 3 deletions care/facility/models/mixins/permissions/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
class PatientPermissionMixin(BasePermissionMixin):
@staticmethod
def has_write_permission(request):
if request.user.asset:
return False
if (
request.user.user_type == User.TYPE_VALUE_MAP["DistrictReadOnlyAdmin"]
or request.user.user_type == User.TYPE_VALUE_MAP["StateReadOnlyAdmin"]
Expand Down Expand Up @@ -38,6 +40,8 @@ def has_object_read_permission(self, request):
)

def has_object_write_permission(self, request):
if request.user.asset:
return False
doctor_allowed = False
if self.last_consultation:
doctor_allowed = self.last_consultation.assigned_to == request.user or request.user == self.assigned_to
Expand Down Expand Up @@ -65,6 +69,8 @@ def has_object_write_permission(self, request):
)

def has_object_update_permission(self, request):
if request.user.asset:
return False
doctor_allowed = False
if self.last_consultation:
doctor_allowed = self.last_consultation.assigned_to == request.user or request.user == self.assigned_to
Expand Down Expand Up @@ -96,16 +102,16 @@ def has_object_icmr_sample_permission(self, request):
return self.has_object_read_permission(request)

def has_object_transfer_permission(self, request):
if request.user.asset:
return False
if (
request.user.user_type == User.TYPE_VALUE_MAP["DistrictReadOnlyAdmin"]
or request.user.user_type == User.TYPE_VALUE_MAP["StateReadOnlyAdmin"]
or request.user.user_type == User.TYPE_VALUE_MAP["StaffReadOnly"]
):
return False
new_facility = Facility.objects.filter(id=request.data.get("facility", None)).first()
return self.has_object_update_permission(request) or (
new_facility and request.user in new_facility.users.all()
)
return self.has_object_update_permission(request) or (new_facility and request.user in new_facility.users.all())


class PatientRelatedPermissionMixin(BasePermissionMixin):
Expand Down
112 changes: 90 additions & 22 deletions care/facility/models/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@ class TestTypeEnum(enum.Enum):
source = models.IntegerField(choices=SourceChoices, default=SourceEnum.CARE.value)
facility = models.ForeignKey("Facility", on_delete=models.SET_NULL, null=True)
nearest_facility = models.ForeignKey(
"Facility", on_delete=models.SET_NULL, null=True, related_name="nearest_facility",
"Facility",
on_delete=models.SET_NULL,
null=True,
related_name="nearest_facility",
)
meta_info = models.OneToOneField("PatientMetaInfo", on_delete=models.SET_NULL, null=True)

Expand Down Expand Up @@ -120,7 +123,11 @@ class TestTypeEnum(enum.Enum):
is_medical_worker = models.BooleanField(default=False, verbose_name="Is the Patient a Medical Worker")

blood_group = models.CharField(
choices=BLOOD_GROUP_CHOICES, null=True, blank=False, max_length=4, verbose_name="Blood Group of Patient",
choices=BLOOD_GROUP_CHOICES,
null=True,
blank=False,
max_length=4,
verbose_name="Blood Group of Patient",
)

contact_with_confirmed_carrier = models.BooleanField(
Expand All @@ -132,14 +139,20 @@ class TestTypeEnum(enum.Enum):
estimated_contact_date = models.DateTimeField(null=True, blank=True)

past_travel = models.BooleanField(
default=False, verbose_name="Travelled to Any Foreign Countries in the last 28 Days",
default=False,
verbose_name="Travelled to Any Foreign Countries in the last 28 Days",
)
countries_travelled_old = models.TextField(
null=True, blank=True, verbose_name="Countries Patient has Travelled to", editable=False,
null=True,
blank=True,
verbose_name="Countries Patient has Travelled to",
editable=False,
)
countries_travelled = JSONField(null=True, blank=True, verbose_name="Countries Patient has Travelled to")
date_of_return = models.DateTimeField(
blank=True, null=True, verbose_name="Return Date from the Last Country if Travelled",
blank=True,
null=True,
verbose_name="Return Date from the Last Country if Travelled",
)

allergies = models.TextField(default="", blank=True, verbose_name="Patient's Known Allergies")
Expand All @@ -157,27 +170,43 @@ class TestTypeEnum(enum.Enum):
district = models.ForeignKey(District, on_delete=models.SET_NULL, null=True, blank=True)
state = models.ForeignKey(State, on_delete=models.SET_NULL, null=True, blank=True)

is_migrant_worker = models.BooleanField(default=False, verbose_name="Is Patient a Migrant Worker",)
is_migrant_worker = models.BooleanField(
default=False,
verbose_name="Is Patient a Migrant Worker",
)

disease_status = models.IntegerField(
choices=DISEASE_STATUS_CHOICES, default=1, blank=True, verbose_name="Disease Status",
choices=DISEASE_STATUS_CHOICES,
default=1,
blank=True,
verbose_name="Disease Status",
)

number_of_aged_dependents = models.IntegerField(
default=0, verbose_name="Number of people aged above 60 living with the patient", blank=True,
default=0,
verbose_name="Number of people aged above 60 living with the patient",
blank=True,
)
number_of_chronic_diseased_dependents = models.IntegerField(
default=0, verbose_name="Number of people who have chronic diseases living with the patient", blank=True,
default=0,
verbose_name="Number of people who have chronic diseases living with the patient",
blank=True,
)

last_edited = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name="patient_last_edited_by",)
last_edited = models.ForeignKey(
User,
on_delete=models.SET_NULL,
null=True,
related_name="patient_last_edited_by",
)

action = models.IntegerField(choices=ActionChoices, default=ActionEnum.PENDING.value)
review_time = models.DateTimeField(null=True, blank=True, verbose_name="Patient's next review time")

created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name="patient_created_by")
is_active = models.BooleanField(
default=True, help_text="Not active when discharged, or removed from the watchlist",
default=True,
help_text="Not active when discharged, or removed from the watchlist",
)

patient_search_id = EncryptedIntegerField(help_text="FKey to PatientSearch", null=True)
Expand All @@ -197,16 +226,24 @@ class TestTypeEnum(enum.Enum):
last_consultation = models.ForeignKey(PatientConsultation, on_delete=models.SET_NULL, null=True, default=None)

will_donate_blood = models.BooleanField(
default=None, null=True, verbose_name="Is Patient Willing to donate Blood",
default=None,
null=True,
verbose_name="Is Patient Willing to donate Blood",
)

fit_for_blood_donation = models.BooleanField(
default=None, null=True, verbose_name="Is Patient fit for donating Blood",
default=None,
null=True,
verbose_name="Is Patient fit for donating Blood",
)

# IDSP REQUIREMENTS
village = models.CharField(
max_length=255, default=None, verbose_name="Vilalge Name of Patient (IDSP Req)", null=True, blank=True,
max_length=255,
default=None,
verbose_name="Vilalge Name of Patient (IDSP Req)",
null=True,
blank=True,
)
designation_of_health_care_worker = models.CharField(
max_length=255,
Expand All @@ -216,13 +253,25 @@ class TestTypeEnum(enum.Enum):
blank=True,
)
instituion_of_health_care_worker = models.CharField(
max_length=255, default=None, verbose_name="Institution of Healtcare Worker (IDSP Req)", null=True, blank=True,
max_length=255,
default=None,
verbose_name="Institution of Healtcare Worker (IDSP Req)",
null=True,
blank=True,
)
transit_details = models.CharField(
max_length=255, default=None, verbose_name="Transit Details (IDSP Req)", null=True, blank=True,
max_length=255,
default=None,
verbose_name="Transit Details (IDSP Req)",
null=True,
blank=True,
)
frontline_worker = models.CharField(
max_length=255, default=None, verbose_name="Front Line Worker (IDSP Req)", null=True, blank=True,
max_length=255,
default=None,
verbose_name="Front Line Worker (IDSP Req)",
null=True,
blank=True,
)
date_of_result = models.DateTimeField(null=True, blank=True, default=None, verbose_name="Patient's result Date")
number_of_primary_contacts = models.IntegerField(
Expand All @@ -241,15 +290,27 @@ class TestTypeEnum(enum.Enum):
vaccine_name = models.CharField(choices=vaccineChoices, default=None, null=True, blank=False, max_length=15)

covin_id = models.CharField(
max_length=15, default=None, null=True, blank=True, verbose_name="COVID-19 Vaccination ID",
max_length=15,
default=None,
null=True,
blank=True,
verbose_name="COVID-19 Vaccination ID",
)
last_vaccinated_date = models.DateTimeField(null=True, blank=True, verbose_name="Date Last Vaccinated")

# Extras
cluster_name = models.CharField(
max_length=255, default=None, verbose_name="Name/ Cluster of Contact", null=True, blank=True,
max_length=255,
default=None,
verbose_name="Name/ Cluster of Contact",
null=True,
blank=True,
)
is_declared_positive = models.BooleanField(
default=None,
null=True,
verbose_name="Is Patient Declared Positive",
)
is_declared_positive = models.BooleanField(default=None, null=True, verbose_name="Is Patient Declared Positive",)
date_declared_positive = models.DateTimeField(
null=True, blank=True, verbose_name="Date Patient is Declared Positive"
)
Expand Down Expand Up @@ -525,7 +586,10 @@ class ModeOfContactEnum(enum.IntEnum):

patient = models.ForeignKey(PatientRegistration, on_delete=models.PROTECT, related_name="contacted_patients")
patient_in_contact = models.ForeignKey(
PatientRegistration, on_delete=models.PROTECT, null=True, related_name="contacts",
PatientRegistration,
on_delete=models.PROTECT,
null=True,
related_name="contacts",
)
relation_with_patient = models.IntegerField(choices=RelationChoices)
mode_of_contact = models.IntegerField(choices=ModeOfContactChoices)
Expand Down Expand Up @@ -590,5 +654,9 @@ class PatientMobileOTP(BaseModel):
class PatientNotes(FacilityBaseModel):
patient = models.ForeignKey(PatientRegistration, on_delete=models.PROTECT, null=False, blank=False)
facility = models.ForeignKey(Facility, on_delete=models.PROTECT, null=False, blank=False)
created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True,)
created_by = models.ForeignKey(
User,
on_delete=models.SET_NULL,
null=True,
)
note = models.TextField(default="", blank=True)
20 changes: 20 additions & 0 deletions care/users/migrations/0041_user_asset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 2.2.11 on 2022-03-22 09:40

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('facility', '0285_asset_asset_class'),
('users', '0040_auto_20210616_1821'),
]

operations = [
migrations.AddField(
model_name='user',
name='asset',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='facility.Asset', unique=True),
),
]
6 changes: 6 additions & 0 deletions care/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ class User(AbstractUser):
pf_p256dh = models.TextField(default=None, null=True)
pf_auth = models.TextField(default=None, null=True)

# Asset Fields

asset = models.ForeignKey(
"facility.Asset", default=None, null=True, blank=True, on_delete=models.PROTECT, unique=True
)

objects = CustomUserManager()

REQUIRED_FIELDS = [
Expand Down
Loading

0 comments on commit 9e03d62

Please sign in to comment.