diff --git a/.gitattributes b/.gitattributes index a8d4103c3d..efdba87644 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ * text=auto -scripts/* text eol=lf +*.sh text eol=lf diff --git a/.gitignore b/.gitignore index 84a84d610f..4723ff931c 100644 --- a/.gitignore +++ b/.gitignore @@ -344,7 +344,7 @@ care/media/* test_db -celerybeat-schedule +celerybeat-schedule* secrets.sh diff --git a/Makefile b/Makefile index 12d25fc83b..64008da21b 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,9 @@ up: down: docker compose -f docker-compose.yaml -f $(docker_config_file) down +teardown: + docker compose -f docker-compose.yaml -f $(docker_config_file) down -v + load-dummy-data: docker compose exec backend bash -c "python manage.py load_dummy_data" diff --git a/README.md b/README.md index 17455a29ea..ed20fe7431 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,16 @@ to load dummy data for testing run: ```bash make load-dummy-data ``` +Stops and removes the containers without affecting the volumes: + +```bash +make down +``` +Stops and removes the containers and their volumes: + +```bash +make teardown +``` #### Docker diff --git a/care/facility/api/serializers/patient.py b/care/facility/api/serializers/patient.py index 926e9b21bb..0316667cfa 100644 --- a/care/facility/api/serializers/patient.py +++ b/care/facility/api/serializers/patient.py @@ -16,7 +16,6 @@ GENDER_CHOICES, Disease, Facility, - FacilityPatientStatsHistory, PatientContactDetails, PatientMetaInfo, PatientNotes, @@ -358,33 +357,6 @@ def update(self, instance, validated_data): return patient -class FacilityPatientStatsHistorySerializer(serializers.ModelSerializer): - id = serializers.CharField(source="external_id", read_only=True) - entry_date = serializers.DateField(default=lambda: now().date()) - facility = ExternalIdSerializerField( - queryset=Facility.objects.all(), read_only=True - ) - - class Meta: - model = FacilityPatientStatsHistory - exclude = ( - "deleted", - "external_id", - ) - read_only_fields = ( - "id", - "facility", - ) - - def create(self, validated_data): - instance, _ = FacilityPatientStatsHistory.objects.update_or_create( - facility=validated_data["facility"], - entry_date=validated_data["entry_date"], - defaults={**validated_data, "deleted": False}, - ) - return instance - - class PatientSearchSerializer(serializers.ModelSerializer): gender = ChoiceField(choices=GENDER_CHOICES) patient_id = serializers.UUIDField(source="external_id", read_only=True) diff --git a/care/facility/api/serializers/summary.py b/care/facility/api/serializers/summary.py deleted file mode 100644 index 0a4f367402..0000000000 --- a/care/facility/api/serializers/summary.py +++ /dev/null @@ -1,24 +0,0 @@ -from rest_framework import serializers - -from care.facility.api.serializers.facility import FacilitySerializer -from care.facility.models import DistrictScopedSummary, FacilityRelatedSummary - - -class FacilitySummarySerializer(serializers.ModelSerializer): - facility = FacilitySerializer() - - class Meta: - model = FacilityRelatedSummary - exclude = ( - "id", - "s_type", - ) - - -class DistrictSummarySerializer(serializers.ModelSerializer): - class Meta: - model = DistrictScopedSummary - exclude = ( - "id", - "s_type", - ) diff --git a/care/facility/api/viewsets/facility.py b/care/facility/api/viewsets/facility.py index 1f0ac69442..ff3c09ee2a 100644 --- a/care/facility/api/viewsets/facility.py +++ b/care/facility/api/viewsets/facility.py @@ -21,7 +21,6 @@ from care.facility.models import ( Facility, FacilityCapacity, - FacilityPatientStatsHistory, HospitalDoctors, ) from care.facility.models.facility import FacilityHubSpoke, FacilityUser @@ -134,11 +133,6 @@ def list(self, request, *args, **kwargs): elif self.FACILITY_DOCTORS_CSV_KEY in request.GET: mapping.update(HospitalDoctors.CSV_RELATED_MAPPING.copy()) pretty_mapping.update(HospitalDoctors.CSV_MAKE_PRETTY.copy()) - elif self.FACILITY_TRIAGE_CSV_KEY in request.GET: - mapping.update(FacilityPatientStatsHistory.CSV_RELATED_MAPPING.copy()) - pretty_mapping.update( - FacilityPatientStatsHistory.CSV_MAKE_PRETTY.copy() - ) queryset = self.filter_queryset(self.get_queryset()).values(*mapping.keys()) return render_to_csv_response( queryset, field_header_map=mapping, field_serializer_map=pretty_mapping diff --git a/care/facility/api/viewsets/patient.py b/care/facility/api/viewsets/patient.py index 6f30ab8c25..7b023c1531 100644 --- a/care/facility/api/viewsets/patient.py +++ b/care/facility/api/viewsets/patient.py @@ -23,7 +23,7 @@ from drf_spectacular.utils import extend_schema, extend_schema_view from dry_rest_permissions.generics import DRYPermissionFiltersBase, DRYPermissions from rest_framework import filters as rest_framework_filters -from rest_framework import mixins, serializers, status, viewsets +from rest_framework import mixins, serializers, status from rest_framework.decorators import action from rest_framework.exceptions import ValidationError from rest_framework.filters import BaseFilterBackend @@ -40,7 +40,6 @@ from rest_framework.viewsets import GenericViewSet from care.facility.api.serializers.patient import ( - FacilityPatientStatsHistorySerializer, PatientDetailSerializer, PatientListSerializer, PatientNotesEditSerializer, @@ -58,7 +57,6 @@ BedTypeChoices, DailyRound, Facility, - FacilityPatientStatsHistory, PatientNotes, PatientNoteThreadChoices, PatientRegistration, @@ -730,62 +728,6 @@ def get_queryset(self) -> QuerySet: ) -class FacilityPatientStatsHistoryFilterSet(filters.FilterSet): - entry_date = filters.DateFromToRangeFilter(field_name="entry_date") - - -class FacilityPatientStatsHistoryViewSet(viewsets.ModelViewSet): - lookup_field = "external_id" - permission_classes = (IsAuthenticated, DRYPermissions) - queryset = FacilityPatientStatsHistory.objects.filter( - facility__deleted=False - ).order_by("-entry_date") - serializer_class = FacilityPatientStatsHistorySerializer - filter_backends = (filters.DjangoFilterBackend,) - filterset_class = FacilityPatientStatsHistoryFilterSet - http_method_names = ["get", "post", "delete"] - - def get_queryset(self): - user = self.request.user - queryset = self.queryset.filter( - facility__external_id=self.kwargs.get("facility_external_id") - ) - if user.is_superuser: - return queryset - if self.request.user.user_type >= User.TYPE_VALUE_MAP["StateLabAdmin"]: - return queryset.filter(facility__state=user.state) - if 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) - - def get_object(self): - return get_object_or_404( - self.get_queryset(), external_id=self.kwargs.get("external_id") - ) - - def get_facility(self): - facility_qs = Facility.objects.filter( - external_id=self.kwargs.get("facility_external_id") - ) - if not self.request.user.is_superuser: - facility_qs.filter(users__id__exact=self.request.user.id) - return get_object_or_404(facility_qs) - - def perform_create(self, serializer): - return serializer.save(facility=self.get_facility()) - - def list(self, request, *args, **kwargs): - """ - Patient Stats - List - - Available Filters - - entry_date_before: date in YYYY-MM-DD format, inclusive of this date - - entry_date_before: date in YYYY-MM-DD format, inclusive of this date - - """ - return super().list(request, *args, **kwargs) - - class PatientSearchSetPagination(PageNumberPagination): page_size = 200 diff --git a/care/facility/api/viewsets/summary.py b/care/facility/api/viewsets/summary.py deleted file mode 100644 index fbc60f6bb3..0000000000 --- a/care/facility/api/viewsets/summary.py +++ /dev/null @@ -1,126 +0,0 @@ -from django.utils.decorators import method_decorator -from django.views.decorators.cache import cache_page -from django_filters import rest_framework as filters -from drf_spectacular.utils import extend_schema -from rest_framework.mixins import ListModelMixin -from rest_framework.permissions import IsAuthenticatedOrReadOnly -from rest_framework.viewsets import GenericViewSet - -from care.facility.api.serializers.summary import ( - DistrictSummarySerializer, - FacilitySummarySerializer, -) -from care.facility.models import DistrictScopedSummary, FacilityRelatedSummary - - -class FacilitySummaryFilter(filters.FilterSet): - start_date = filters.DateFilter(field_name="created_date", lookup_expr="gte") - end_date = filters.DateFilter(field_name="created_date", lookup_expr="lte") - facility = filters.UUIDFilter(field_name="facility__external_id") - district = filters.NumberFilter(field_name="facility__district__id") - local_body = filters.NumberFilter(field_name="facility__local_body__id") - state = filters.NumberFilter(field_name="facility__state__id") - - -class FacilityCapacitySummaryViewSet( - ListModelMixin, - GenericViewSet, -): - lookup_field = "external_id" - queryset = ( - FacilityRelatedSummary.objects.filter(s_type="FacilityCapacity") - .order_by("-created_date") - .select_related( - "facility", - "facility__state", - "facility__district", - "facility__local_body", - ) - ) - permission_classes = (IsAuthenticatedOrReadOnly,) - serializer_class = FacilitySummarySerializer - - filter_backends = (filters.DjangoFilterBackend,) - filterset_class = FacilitySummaryFilter - - @extend_schema(tags=["summary"]) - @method_decorator(cache_page(60 * 10)) - def list(self, request, *args, **kwargs): - return super().list(request, *args, **kwargs) - - -class TriageSummaryViewSet(ListModelMixin, GenericViewSet): - lookup_field = "external_id" - queryset = FacilityRelatedSummary.objects.filter(s_type="TriageSummary").order_by( - "-created_date" - ) - permission_classes = (IsAuthenticatedOrReadOnly,) - serializer_class = FacilitySummarySerializer - - filter_backends = (filters.DjangoFilterBackend,) - filterset_class = FacilitySummaryFilter - - @extend_schema(tags=["summary"]) - @method_decorator(cache_page(60 * 60)) - def list(self, request, *args, **kwargs): - return super().list(request, *args, **kwargs) - - -class TestsSummaryViewSet(ListModelMixin, GenericViewSet): - lookup_field = "external_id" - queryset = FacilityRelatedSummary.objects.filter(s_type="TestSummary").order_by( - "-created_date" - ) - permission_classes = (IsAuthenticatedOrReadOnly,) - serializer_class = FacilitySummarySerializer - - filter_backends = (filters.DjangoFilterBackend,) - filterset_class = FacilitySummaryFilter - - @extend_schema(tags=["summary"]) - @method_decorator(cache_page(60 * 60 * 10)) - def list(self, request, *args, **kwargs): - return super().list(request, *args, **kwargs) - - -class PatientSummaryViewSet(ListModelMixin, GenericViewSet): - lookup_field = "external_id" - queryset = FacilityRelatedSummary.objects.filter(s_type="PatientSummary").order_by( - "-created_date" - ) - permission_classes = (IsAuthenticatedOrReadOnly,) - serializer_class = FacilitySummarySerializer - - filter_backends = (filters.DjangoFilterBackend,) - filterset_class = FacilitySummaryFilter - - @extend_schema(tags=["summary"]) - @method_decorator(cache_page(60 * 10)) - def list(self, request, *args, **kwargs): - return super().list(request, *args, **kwargs) - - -class DistrictSummaryFilter(filters.FilterSet): - start_date = filters.DateFilter(field_name="created_date", lookup_expr="gte") - end_date = filters.DateFilter(field_name="created_date", lookup_expr="lte") - district = filters.NumberFilter(field_name="district__id") - state = filters.NumberFilter(field_name="district__state__id") - - -class DistrictPatientSummaryViewSet(ListModelMixin, GenericViewSet): - lookup_field = "external_id" - queryset = ( - DistrictScopedSummary.objects.filter(s_type="PatientSummary") - .order_by("-created_date") - .select_related("district", "district__state") - ) - permission_classes = (IsAuthenticatedOrReadOnly,) - serializer_class = DistrictSummarySerializer - - filter_backends = (filters.DjangoFilterBackend,) - filterset_class = DistrictSummaryFilter - - @extend_schema(tags=["summary"]) - @method_decorator(cache_page(60 * 10)) - def list(self, request, *args, **kwargs): - return super().list(request, *args, **kwargs) diff --git a/care/facility/management/commands/summarize.py b/care/facility/management/commands/summarize.py deleted file mode 100644 index d008e21df5..0000000000 --- a/care/facility/management/commands/summarize.py +++ /dev/null @@ -1,25 +0,0 @@ -from django.core.management.base import BaseCommand - -from care.facility.utils.summarization.district.patient_summary import ( - district_patient_summary, -) -from care.facility.utils.summarization.facility_capacity import ( - facility_capacity_summary, -) -from care.facility.utils.summarization.patient_summary import patient_summary - - -class Command(BaseCommand): - """ - Management command to Force Create Summary objects. - """ - - help = "Force Create Summary Objects" - - def handle(self, *args, **options): - patient_summary() - self.stdout.write("Patients Summarised") - facility_capacity_summary() - self.stdout.write("Capacity Summarised") - district_patient_summary() - self.stdout.write("District Wise Patient Summarised") diff --git a/care/facility/migrations/0468_alter_facilitypatientstatshistory_unique_together_and_more.py b/care/facility/migrations/0468_alter_facilitypatientstatshistory_unique_together_and_more.py new file mode 100644 index 0000000000..66f9e75e1c --- /dev/null +++ b/care/facility/migrations/0468_alter_facilitypatientstatshistory_unique_together_and_more.py @@ -0,0 +1,41 @@ +# Generated by Django 5.1.3 on 2024-12-15 17:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('facility', '0467_alter_hospitaldoctors_area'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='facilitypatientstatshistory', + unique_together=None, + ), + migrations.RemoveField( + model_name='facilitypatientstatshistory', + name='facility', + ), + migrations.RemoveField( + model_name='facilityrelatedsummary', + name='facility', + ), + migrations.RemoveField( + model_name='localbodyscopedsummary', + name='lsg', + ), + migrations.DeleteModel( + name='DistrictScopedSummary', + ), + migrations.DeleteModel( + name='FacilityPatientStatsHistory', + ), + migrations.DeleteModel( + name='FacilityRelatedSummary', + ), + migrations.DeleteModel( + name='LocalBodyScopedSummary', + ), + ] diff --git a/care/facility/models/__init__.py b/care/facility/models/__init__.py index d6d63cacca..959e5c4e0b 100644 --- a/care/facility/models/__init__.py +++ b/care/facility/models/__init__.py @@ -20,4 +20,3 @@ from .prescription import * # noqa from .resources import * # noqa from .shifting import * # noqa -from .summary import * # noqa diff --git a/care/facility/models/patient.py b/care/facility/models/patient.py index 4f8d54c971..4e8f98c130 100644 --- a/care/facility/models/patient.py +++ b/care/facility/models/patient.py @@ -24,9 +24,6 @@ Ward, ) from care.facility.models.icd11_diagnosis import ConditionVerificationStatus -from care.facility.models.mixins.permissions.facility import ( - FacilityRelatedPermissionMixin, -) from care.facility.models.mixins.permissions.patient import ( ConsultationRelatedPermissionMixin, PatientPermissionMixin, @@ -737,33 +734,6 @@ def get_disease_display(self): return DISEASE_CHOICES[self.disease - 1][1] -class FacilityPatientStatsHistory(FacilityBaseModel, FacilityRelatedPermissionMixin): - facility = models.ForeignKey("Facility", on_delete=models.PROTECT) - entry_date = models.DateField() - num_patients_visited = models.IntegerField(default=0) - num_patients_home_quarantine = models.IntegerField(default=0) - num_patients_isolation = models.IntegerField(default=0) - num_patient_referred = models.IntegerField(default=0) - num_patient_confirmed_positive = models.IntegerField(default=0) - - CSV_RELATED_MAPPING = { - "facilitypatientstatshistory__entry_date": "Entry Date", - "facilitypatientstatshistory__num_patients_visited": "Vistited Patients", - "facilitypatientstatshistory__num_patients_home_quarantine": "Home Quarantined Patients", - "facilitypatientstatshistory__num_patients_isolation": "Patients Isolated", - "facilitypatientstatshistory__num_patient_referred": "Patients Referred", - "facilitypatientstatshistory__num_patient_confirmed_positive": "Patients Confirmed Positive", - } - - CSV_MAKE_PRETTY = {} - - class Meta: - unique_together = ( - "facility", - "entry_date", - ) - - class PatientMobileOTP(BaseModel): is_used = models.BooleanField(default=False) phone_number = models.CharField( diff --git a/care/facility/models/summary.py b/care/facility/models/summary.py deleted file mode 100644 index 2cd1071bad..0000000000 --- a/care/facility/models/summary.py +++ /dev/null @@ -1,120 +0,0 @@ -from uuid import uuid4 - -from django.db import models -from django.db.models import JSONField - -from care.facility.models.facility import Facility -from care.users.models import District, LocalBody - -SUMMARY_CHOICES = ( - ("FacilityCapacity", "FacilityCapacity"), - ("PatientSummary", "PatientSummary"), - ("TestSummary", "TestSummary"), - ("TriageSummary", "TriageSummary"), -) - - -class FacilityRelatedSummary(models.Model): - id = models.UUIDField(primary_key=True, default=uuid4, unique=True, db_index=True) - created_date = models.DateTimeField(auto_now_add=True, null=True, blank=True) - modified_date = models.DateTimeField(auto_now=True, null=True, blank=True) - facility = models.ForeignKey( - Facility, on_delete=models.CASCADE, null=True, blank=True - ) - s_type = models.CharField(choices=SUMMARY_CHOICES, max_length=100) - data = JSONField(null=True, blank=True, default=dict) - - class Meta: - indexes = [ - models.Index( - fields=[ - "-modified_date", - ] - ), - models.Index( - fields=[ - "-created_date", - ] - ), - models.Index( - fields=[ - "s_type", - ] - ), - models.Index(fields=["-created_date", "s_type"]), - ] - - def __str__(self): - return f"FacilityRelatedSummary - {self.facility} - {self.s_type}" - - -DISTRICT_SUMMARY_CHOICES = (("PatientSummary", "PatientSummary"),) - - -class DistrictScopedSummary(models.Model): - id = models.UUIDField(primary_key=True, default=uuid4, unique=True, db_index=True) - created_date = models.DateTimeField(auto_now_add=True, null=True, blank=True) - modified_date = models.DateTimeField(auto_now=True, null=True, blank=True) - district = models.ForeignKey( - District, on_delete=models.CASCADE, null=True, blank=True - ) - s_type = models.CharField(choices=DISTRICT_SUMMARY_CHOICES, max_length=100) - data = JSONField(null=True, blank=True, default=dict) - - class Meta: - indexes = [ - models.Index( - fields=[ - "-modified_date", - ] - ), - models.Index( - fields=[ - "-created_date", - ] - ), - models.Index( - fields=[ - "s_type", - ] - ), - models.Index(fields=["-created_date", "s_type"]), - ] - - def __str__(self): - return f"DistrictScopedSummary - {self.district} - {self.s_type}" - - -LSG_SUMMARY_CHOICES = (("PatientSummary", "PatientSummary"),) - - -class LocalBodyScopedSummary(models.Model): - id = models.UUIDField(primary_key=True, default=uuid4, unique=True, db_index=True) - created_date = models.DateTimeField(auto_now_add=True, null=True, blank=True) - modified_date = models.DateTimeField(auto_now=True, null=True, blank=True) - lsg = models.ForeignKey(LocalBody, on_delete=models.CASCADE, null=True, blank=True) - s_type = models.CharField(choices=LSG_SUMMARY_CHOICES, max_length=100) - data = JSONField(null=True, blank=True, default=dict) - - class Meta: - indexes = [ - models.Index( - fields=[ - "-modified_date", - ] - ), - models.Index( - fields=[ - "-created_date", - ] - ), - models.Index( - fields=[ - "s_type", - ] - ), - models.Index(fields=["-created_date", "s_type"]), - ] - - def __str__(self): - return f"LocalBodyScopedSummary - {self.lsg} - {self.s_type}" diff --git a/care/facility/tasks/__init__.py b/care/facility/tasks/__init__.py index f4e4774935..26dc090bc4 100644 --- a/care/facility/tasks/__init__.py +++ b/care/facility/tasks/__init__.py @@ -7,13 +7,6 @@ from care.facility.tasks.location_monitor import check_location_status from care.facility.tasks.plausible_stats import capture_goals from care.facility.tasks.redis_index import load_redis_index -from care.facility.tasks.summarisation import ( - summarize_district_patient, - summarize_facility_capacity, - summarize_patient, - summarize_tests, - summarize_triage, -) @current_app.on_after_finalize.connect @@ -23,36 +16,6 @@ def setup_periodic_tasks(sender, **kwargs): delete_old_notifications.s(), name="delete_old_notifications", ) - if settings.TASK_SUMMARIZE_TRIAGE: - sender.add_periodic_task( - crontab(hour="*/4", minute="59"), - summarize_triage.s(), - name="summarise_triage", - ) - if settings.TASK_SUMMARIZE_TESTS: - sender.add_periodic_task( - crontab(hour="23", minute="59"), - summarize_tests.s(), - name="summarise_tests", - ) - if settings.TASK_SUMMARIZE_FACILITY_CAPACITY: - sender.add_periodic_task( - crontab(minute="*/5"), - summarize_facility_capacity.s(), - name="summarise_facility_capacity", - ) - if settings.TASK_SUMMARIZE_PATIENT: - sender.add_periodic_task( - crontab(hour="*/1", minute="59"), - summarize_patient.s(), - name="summarise_patient", - ) - if settings.TASK_SUMMARIZE_DISTRICT_PATIENT: - sender.add_periodic_task( - crontab(hour="*/1", minute="59"), - summarize_district_patient.s(), - name="summarise_district_patient", - ) sender.add_periodic_task( crontab(minute="*/30"), diff --git a/care/facility/tasks/summarisation.py b/care/facility/tasks/summarisation.py deleted file mode 100644 index 541d032157..0000000000 --- a/care/facility/tasks/summarisation.py +++ /dev/null @@ -1,44 +0,0 @@ -from celery import shared_task -from celery.utils.log import get_task_logger - -from care.facility.utils.summarization.district.patient_summary import ( - district_patient_summary, -) -from care.facility.utils.summarization.facility_capacity import ( - facility_capacity_summary, -) -from care.facility.utils.summarization.patient_summary import patient_summary -from care.facility.utils.summarization.tests_summary import tests_summary -from care.facility.utils.summarization.triage_summary import triage_summary - -logger = get_task_logger(__name__) - - -@shared_task -def summarize_triage(): - triage_summary() - logger.info("Summarized Triages") - - -@shared_task -def summarize_tests(): - tests_summary() - logger.info("Summarized Tests") - - -@shared_task -def summarize_facility_capacity(): - facility_capacity_summary() - logger.info("Summarized Facility Capacities") - - -@shared_task -def summarize_patient(): - patient_summary() - logger.info("Summarized Patients") - - -@shared_task -def summarize_district_patient(): - district_patient_summary() - logger.info("Summarized District Patients") diff --git a/care/facility/utils/summarization/__init__.py b/care/facility/utils/summarization/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/care/facility/utils/summarization/district/__init__.py b/care/facility/utils/summarization/district/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/care/facility/utils/summarization/district/patient_summary.py b/care/facility/utils/summarization/district/patient_summary.py deleted file mode 100644 index a4f20a8d37..0000000000 --- a/care/facility/utils/summarization/district/patient_summary.py +++ /dev/null @@ -1,104 +0,0 @@ -from django.db.models import Q -from django.utils.timezone import now - -from care.facility.models import DistrictScopedSummary, PatientRegistration -from care.facility.models.patient_base import BedTypeChoices -from care.users.models import District, LocalBody - - -def district_patient_summary(): - for district_object in District.objects.all(): - district_summary = { - "name": district_object.name, - "id": district_object.id, - } - for local_body_object in LocalBody.objects.filter( - district_id=district_object.id - ): - district_summary[local_body_object.id] = { - "name": local_body_object.name, - "code": local_body_object.localbody_code, - "total_inactive": PatientRegistration.objects.filter( - is_active=False, - local_body_id=local_body_object.id, - ).count(), - } - patients = PatientRegistration.objects.filter( - is_active=True, - last_consultation__discharge_date__isnull=True, - local_body_id=local_body_object.id, - ) - - # Get Total Counts - - for bed_type_choice in BedTypeChoices: - db_value, text = bed_type_choice - patient_filters = { - "last_consultation__" + "current_bed__bed__bed_type": db_value - } - count = patients.filter(**patient_filters).count() - clean_name = "total_patients_" + "_".join(text.lower().split()) - district_summary[local_body_object.id][clean_name] = count - - home_quarantine = Q(last_consultation__suggestion="HI") - - total_patients_home_quarantine = patients.filter(home_quarantine).count() - district_summary[local_body_object.id]["total_patients_home_quarantine"] = ( - total_patients_home_quarantine - ) - - # Apply Date Filters - - patients_today = patients.filter( - last_consultation__created_date__startswith=now().date() - ) - - # Get Todays Counts - - today_patients_home_quarantine = patients_today.filter( - home_quarantine - ).count() - - for bed_type_choice in BedTypeChoices: - db_value, text = bed_type_choice - patient_filters = { - "last_consultation__" + "current_bed__bed__bed_type": db_value - } - count = patients_today.filter(**patient_filters).count() - clean_name = "today_patients_" + "_".join(text.lower().split()) - district_summary[local_body_object.id][clean_name] = count - - # Update Anything Extra - district_summary[local_body_object.id]["today_patients_home_quarantine"] = ( - today_patients_home_quarantine - ) - - object_filter = Q(s_type="PatientSummary") & Q( - created_date__startswith=now().date() - ) - if ( - DistrictScopedSummary.objects.filter(district_id=district_object.id) - .filter(object_filter) - .exists() - ): - district_summary_old = DistrictScopedSummary.objects.filter( - object_filter - ).get(district_id=district_object.id) - district_summary_old.created_date = now() - district_summary_old.data.pop("modified_date") - - district_summary_old.data = district_summary - latest_modification_date = now() - district_summary_old.data.update( - {"modified_date": latest_modification_date.strftime("%d-%m-%Y %H:%M")} - ) - district_summary_old.save() - else: - modified_date = now() - district_summary["modified_date"] = modified_date.strftime("%d-%m-%Y %H:%M") - DistrictScopedSummary( - s_type="PatientSummary", - district_id=district_object.id, - data=district_summary, - ).save() - return True diff --git a/care/facility/utils/summarization/facility_capacity.py b/care/facility/utils/summarization/facility_capacity.py deleted file mode 100644 index 44df537cc6..0000000000 --- a/care/facility/utils/summarization/facility_capacity.py +++ /dev/null @@ -1,121 +0,0 @@ -from django.db.models import Sum -from django.utils.timezone import localtime, now - -from care.facility.api.serializers.facility import FacilitySerializer -from care.facility.api.serializers.facility_capacity import FacilityCapacitySerializer -from care.facility.models import ( - Facility, - FacilityCapacity, - FacilityRelatedSummary, - PatientRegistration, -) -from care.facility.models.inventory import ( - FacilityInventoryBurnRate, - FacilityInventoryLog, - FacilityInventorySummary, -) - - -def facility_capacity_summary(): - capacity_objects = FacilityCapacity.objects.all() - capacity_summary = {} - current_date = localtime(now()).replace(hour=0, minute=0, second=0, microsecond=0) - - for facility_obj in Facility.objects.all(): - # Calculate Actual Patients Discharged and Live in this Facility - patients_in_facility = PatientRegistration.objects.filter( - facility_id=facility_obj.id - ).select_related("state", "district", "local_body") - capacity_summary[facility_obj.id] = FacilitySerializer(facility_obj).data - capacity_summary[facility_obj.id]["features"] = list( - capacity_summary[facility_obj.id]["features"] - ) - capacity_summary[facility_obj.id]["actual_live_patients"] = ( - patients_in_facility.filter(is_active=True).count() - ) - discharge_patients = patients_in_facility.filter(is_active=False) - capacity_summary[facility_obj.id]["actual_discharged_patients"] = ( - discharge_patients.count() - ) - capacity_summary[facility_obj.id]["availability"] = [] - - temp_inventory_summary_obj = {} - summary_objs = FacilityInventorySummary.objects.filter( - facility_id=facility_obj.id - ) - for summary_obj in summary_objs: - burn_rate = FacilityInventoryBurnRate.objects.filter( - facility_id=facility_obj.id, item_id=summary_obj.item.id - ).first() - log_query = FacilityInventoryLog.objects.filter( - facility_id=facility_obj.id, - item_id=summary_obj.item.id, - created_date__gte=current_date, - probable_accident=False, - ) - end_log = log_query.order_by("-created_date").first() - end_stock = summary_obj.quantity - if end_log: - end_stock = end_log.current_stock - total_consumed = 0 - temp1 = log_query.filter(is_incoming=False).aggregate( - Sum("quantity_in_default_unit") - ) - if temp1: - total_consumed = temp1.get("quantity_in_default_unit__sum", 0) or 0 - total_added = 0 - temp2 = log_query.filter(is_incoming=True).aggregate( - Sum("quantity_in_default_unit") - ) - if temp2: - total_added = temp2.get("quantity_in_default_unit__sum", 0) or 0 - - start_stock = end_stock - total_added + total_consumed - - if burn_rate: - burn_rate = burn_rate.burn_rate - temp_inventory_summary_obj[summary_obj.item.id] = { - "item_name": summary_obj.item.name, - "stock": summary_obj.quantity, - "unit": summary_obj.item.default_unit.name, - "is_low": summary_obj.is_low, - "burn_rate": burn_rate, - "start_stock": start_stock, - "end_stock": end_stock, - "total_consumed": total_consumed, - "total_added": total_added, - "modified_date": summary_obj.modified_date.astimezone().isoformat(), - } - capacity_summary[facility_obj.id]["inventory"] = temp_inventory_summary_obj - - for capacity_object in capacity_objects: - facility_id = capacity_object.facility_id - if facility_id not in capacity_summary: - # This facility is either deleted or not active - continue - if "availability" not in capacity_summary[facility_id]: - capacity_summary[facility_id]["availability"] = [] - capacity_summary[facility_id]["availability"].append( - FacilityCapacitySerializer(capacity_object).data - ) - - for i in capacity_summary: - facility_summary_obj = None - if FacilityRelatedSummary.objects.filter( - s_type="FacilityCapacity", - facility_id=i, - created_date__gte=current_date, - ).exists(): - facility_summary_obj = FacilityRelatedSummary.objects.get( - s_type="FacilityCapacity", - facility_id=i, - created_date__gte=current_date, - ) - else: - facility_summary_obj = FacilityRelatedSummary( - s_type="FacilityCapacity", facility_id=i - ) - facility_summary_obj.data = capacity_summary[i] - facility_summary_obj.save() - - return True diff --git a/care/facility/utils/summarization/patient_summary.py b/care/facility/utils/summarization/patient_summary.py deleted file mode 100644 index f54f79605b..0000000000 --- a/care/facility/utils/summarization/patient_summary.py +++ /dev/null @@ -1,103 +0,0 @@ -from django.db.models import Q -from django.utils.timezone import now - -from care.facility.models import Facility, FacilityRelatedSummary, PatientRegistration -from care.facility.models.patient_base import BedTypeChoices - - -def patient_summary(): - facility_objects = Facility.objects.all() - patient_summary = {} - for facility_object in facility_objects: - facility_id = facility_object.id - if facility_id not in patient_summary: - patient_summary[facility_id] = { - "facility_name": facility_object.name, - "district": facility_object.district.name, - "facility_external_id": str(facility_object.external_id), - } - - patients = PatientRegistration.objects.filter( - is_active=True, - last_consultation__discharge_date__isnull=True, - last_consultation__facility=facility_object, - ) - - # Get Total Counts - - for bed_type_choice in BedTypeChoices: - db_value, text = bed_type_choice - patient_filters = { - "last_consultation__" + "current_bed__bed__bed_type": db_value - } - count = patients.filter(**patient_filters).count() - clean_name = "total_patients_" + "_".join(text.lower().split()) - patient_summary[facility_id][clean_name] = count - - home_quarantine = Q(last_consultation__suggestion="HI") - - total_patients_home_quarantine = patients.filter(home_quarantine).count() - patient_summary[facility_id]["total_patients_home_quarantine"] = ( - total_patients_home_quarantine - ) - - # Apply Date Filters - - patients_today = patients.filter( - last_consultation__created_date__startswith=now().date() - ) - - # Get Todays Counts - - today_patients_home_quarantine = patients_today.filter( - home_quarantine - ).count() - - for bed_type_choice in BedTypeChoices: - db_value, text = bed_type_choice - patient_filters = { - "last_consultation__" + "current_bed__bed__bed_type": db_value - } - count = patients_today.filter(**patient_filters).count() - clean_name = "today_patients_" + "_".join(text.lower().split()) - patient_summary[facility_id][clean_name] = count - - # Update Anything Extra - patient_summary[facility_id]["today_patients_home_quarantine"] = ( - today_patients_home_quarantine - ) - - for i in list(patient_summary.keys()): - object_filter = Q(s_type="PatientSummary") & Q( - created_date__startswith=now().date() - ) - if ( - FacilityRelatedSummary.objects.filter(facility_id=i) - .filter(object_filter) - .exists() - ): - facility = FacilityRelatedSummary.objects.filter(object_filter).get( - facility_id=i - ) - facility.created_date = now() - facility.data.pop("modified_date") - if facility.data != patient_summary[i]: - facility.data = patient_summary[i] - latest_modification_date = now() - facility.data.update( - { - "modified_date": latest_modification_date.strftime( - "%d-%m-%Y %H:%M" - ) - } - ) - facility.save() - else: - modified_date = now() - patient_summary[i].update( - {"modified_date": modified_date.strftime("%d-%m-%Y %H:%M")} - ) - FacilityRelatedSummary( - s_type="PatientSummary", facility_id=i, data=patient_summary[i] - ).save() - return True diff --git a/care/facility/utils/summarization/tests_summary.py b/care/facility/utils/summarization/tests_summary.py deleted file mode 100644 index a9da8c8a61..0000000000 --- a/care/facility/utils/summarization/tests_summary.py +++ /dev/null @@ -1,64 +0,0 @@ -from django.core.exceptions import ObjectDoesNotExist -from django.utils import timezone - -from care.facility.models import Facility, FacilityRelatedSummary, PatientSample - - -def tests_summary(): - facilities = Facility.objects.all() - for facility in facilities: - facility_total_patients_count = ( - facility.consultations.all().distinct("patient_id").count() - ) - facility_patients_samples = PatientSample.objects.filter( - consultation__facility_id=facility.id - ) - total_tests_count = facility_patients_samples.count() - results_positive_count = facility_patients_samples.filter( - result=PatientSample.SAMPLE_TEST_RESULT_MAP["POSITIVE"] - ).count() - results_awaited_count = facility_patients_samples.filter( - result=PatientSample.SAMPLE_TEST_RESULT_MAP["AWAITING"] - ).count() - results_negative_count = facility_patients_samples.filter( - result=PatientSample.SAMPLE_TEST_RESULT_MAP["NEGATIVE"] - ).count() - test_discarded_count = facility_patients_samples.filter( - result=PatientSample.SAMPLE_TEST_RESULT_MAP["INVALID"] - ).count() - facility_tests_summarised_data = { - "facility_name": facility.name, - "district": facility.district.name, - "total_patients": facility_total_patients_count, - "total_tests": total_tests_count, - "result_positive": results_positive_count, - "result_awaited": results_awaited_count, - "result_negative": results_negative_count, - "test_discarded": test_discarded_count, - } - - try: - facility_test_summary = FacilityRelatedSummary.objects.get( - s_type="TestSummary", - created_date__startswith=timezone.now().date(), - facility=facility, - ) - facility_test_summary.created_date = timezone.now() - facility_test_summary.data.pop("modified_date") - if facility_test_summary.data != facility_tests_summarised_data: - facility_test_summary.data = facility_tests_summarised_data - latest_modification_date = timezone.now() - facility_test_summary.data["modified_date"] = ( - latest_modification_date.strftime("%d-%m-%Y %H:%M") - ) - facility_test_summary.save() - except ObjectDoesNotExist: - modified_date = timezone.now() - facility_tests_summarised_data["modified_date"] = modified_date.strftime( - "%d-%m-%Y %H:%M" - ) - FacilityRelatedSummary.objects.create( - s_type="TestSummary", - facility=facility, - data=facility_tests_summarised_data, - ) diff --git a/care/facility/utils/summarization/triage_summary.py b/care/facility/utils/summarization/triage_summary.py deleted file mode 100644 index df5f4a296c..0000000000 --- a/care/facility/utils/summarization/triage_summary.py +++ /dev/null @@ -1,85 +0,0 @@ -from django.db.models import Count, Sum -from django.utils.timezone import localtime, now - -from care.facility.models import ( - Facility, - FacilityPatientStatsHistory, - FacilityRelatedSummary, -) - - -def triage_summary(): - facilities = Facility.objects.all() - current_date = localtime(now()).replace(hour=0, minute=0, second=0, microsecond=0) - for facility in facilities: - facility_patient_data = FacilityPatientStatsHistory.objects.filter( - facility=facility - ).aggregate( - total_patients_visited=Sum("num_patients_visited"), - total_patients_home_quarantine=Sum("num_patients_home_quarantine"), - total_patients_isolation=Sum("num_patients_isolation"), - total_patients_referred=Sum("num_patient_referred"), - total_patients_confirmed_positive=Sum("num_patient_confirmed_positive"), - total_count=Count("id"), - ) - total_count = facility_patient_data.get("total_count", 0) - total_patients_home_quarantine = facility_patient_data.get( - "total_patients_home_quarantine", 0 - ) - total_patients_referred = facility_patient_data.get( - "total_patients_referred", 0 - ) - total_patients_isolation = facility_patient_data.get( - "total_patients_visited", 0 - ) - total_patients_visited = facility_patient_data.get( - "total_patients_isolation", 0 - ) - total_patients_confirmed_positive = facility_patient_data.get( - "num_patient_confirmed_positive", 0 - ) - if total_count: - avg_patients_home_quarantine = int( - total_patients_home_quarantine / total_count - ) - avg_patients_referred = int(total_patients_referred / total_count) - avg_patients_isolation = int(total_patients_isolation / total_count) - avg_patients_visited = int(total_patients_visited / total_count) - avg_patients_confirmed_positive = int( - total_patients_confirmed_positive / total_count - ) - else: - avg_patients_home_quarantine = 0 - avg_patients_referred = 0 - avg_patients_isolation = 0 - avg_patients_visited = 0 - avg_patients_confirmed_positive = 0 - - facility_triage_summarised_data = { - "facility_name": facility.name, - "district": facility.district.name, - "total_patients_home_quarantine": total_patients_home_quarantine, - "total_patients_referred": total_patients_referred, - "total_patients_isolation": total_patients_isolation, - "total_patients_visited": total_patients_visited, - "total_patients_confirmed_positive": total_patients_confirmed_positive, - "avg_patients_home_quarantine": avg_patients_home_quarantine, - "avg_patients_referred": avg_patients_referred, - "avg_patients_isolation": avg_patients_isolation, - "avg_patients_visited": avg_patients_visited, - "avg_patients_confirmed_positive": avg_patients_confirmed_positive, - } - - facility_triage_summary = FacilityRelatedSummary.objects.filter( - s_type="TriageSummary", facility=facility, created_date__gte=current_date - ).first() - - if facility_triage_summary: - facility_triage_summary.data = facility_triage_summarised_data - else: - facility_triage_summary = FacilityRelatedSummary( - s_type="TriageSummary", - facility=facility, - data=facility_triage_summarised_data, - ) - facility_triage_summary.save() diff --git a/care/utils/notification_handler.py b/care/utils/notification_handler.py index 0ec1718ee0..eca26aa602 100644 --- a/care/utils/notification_handler.py +++ b/care/utils/notification_handler.py @@ -287,7 +287,7 @@ def generate_cause_objects(self): self.caused_objects["patient"] = str( self.caused_object.consultation.patient.external_id ) - self.caused_objects["daily_round"] = str(self.caused_object.id) + self.caused_objects["daily_round"] = str(self.caused_object.external_id) if self.caused_object.consultation.patient.facility: self.caused_objects["facility"] = str( self.caused_object.consultation.facility.external_id diff --git a/config/api_router.py b/config/api_router.py index 94b18f61de..dc41ea0cb8 100644 --- a/config/api_router.py +++ b/config/api_router.py @@ -53,7 +53,6 @@ from care.facility.api.viewsets.notification import NotificationViewSet from care.facility.api.viewsets.patient import ( FacilityDischargedPatientViewSet, - FacilityPatientStatsHistoryViewSet, PatientNotesEditViewSet, PatientNotesViewSet, PatientSearchViewSet, @@ -86,13 +85,6 @@ ShifitngRequestCommentViewSet, ShiftingViewSet, ) -from care.facility.api.viewsets.summary import ( - DistrictPatientSummaryViewSet, - FacilityCapacitySummaryViewSet, - PatientSummaryViewSet, - TestsSummaryViewSet, - TriageSummaryViewSet, -) from care.users.api.viewsets.lsg import ( DistrictViewSet, LocalBodyViewSet, @@ -133,21 +125,6 @@ router.register("notification", NotificationViewSet, basename="notification") -# Summarisation -router.register( - "facility_summary", FacilityCapacitySummaryViewSet, basename="summary-facility" -) -router.register("patient_summary", PatientSummaryViewSet, basename="summary-patient") -router.register("tests_summary", TestsSummaryViewSet, basename="summary-tests") -router.register("triage_summary", TriageSummaryViewSet, basename="summary-triage") - -# District Summary -router.register( - "district_patient_summary", - DistrictPatientSummaryViewSet, - basename="district-summary-patient", -) - router.register("items", FacilityInventoryItemViewSet, basename="items") router.register("shift", ShiftingViewSet, basename="patient-shift") @@ -179,11 +156,6 @@ facility_nested_router.register( r"capacity", FacilityCapacityViewSet, basename="facility-capacity" ) -facility_nested_router.register( - r"patient_stats", - FacilityPatientStatsHistoryViewSet, - basename="facility-patient-stats", -) facility_nested_router.register( r"inventory", FacilityInventoryLogViewSet, basename="facility-inventory" ) diff --git a/config/settings/base.py b/config/settings/base.py index 6983433f86..727ffa2a74 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -640,16 +640,5 @@ PLAUSIBLE_SITE_ID = env("PLAUSIBLE_SITE_ID", default="") PLAUSIBLE_AUTH_TOKEN = env("PLAUSIBLE_AUTH_TOKEN", default="") -# Disable summarization tasks -TASK_SUMMARIZE_TRIAGE = env.bool("TASK_SUMMARIZE_TRIAGE", default=True) -TASK_SUMMARIZE_TESTS = env.bool("TASK_SUMMARIZE_TESTS", default=True) -TASK_SUMMARIZE_FACILITY_CAPACITY = env.bool( - "TASK_SUMMARIZE_FACILITY_CAPACITY", default=True -) -TASK_SUMMARIZE_PATIENT = env.bool("TASK_SUMMARIZE_PATIENT", default=True) -TASK_SUMMARIZE_DISTRICT_PATIENT = env.bool( - "TASK_SUMMARIZE_DISTRICT_PATIENT", default=True -) - # Timeout for middleware request (in seconds) MIDDLEWARE_REQUEST_TIMEOUT = env.int("MIDDLEWARE_REQUEST_TIMEOUT", 20) diff --git a/docker-compose.yaml b/docker-compose.yaml index 25b651fbd6..1633b5d5e3 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -23,20 +23,27 @@ services: ports: - "6380:6379" - localstack: - image: localstack/localstack:latest + minio: + image: minio/minio:latest restart: unless-stopped environment: - - AWS_DEFAULT_REGION=ap-south-1 - - EDGE_PORT=4566 - - SERVICES=s3 - - EXTRA_CORS_ALLOWED_ORIGINS=* - - EXTRA_CORS_ALLOWED_HEADERS=* + MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:-minioadmin} + MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:-minioadmin} + AWS_DEFAULT_REGION: ap-south-1 # To maintain compatibility with existing apps volumes: - - "${TEMPDIR:-./care/media/localstack}:/var/lib/localstack" - - "./docker/awslocal:/etc/localstack/init/ready.d/" + - "./care/media/minio:/data" + - "./docker/minio/init-script.sh:/init-script.sh:ro" # Mount the init script + - "./docker/minio/entrypoint.sh:/entrypoint.sh:ro" # Mount the entrypoint script ports: - - "4566:4566" + - "9100:9000" # S3 API + - "9001:9001" # Web Console + entrypoint: ["/entrypoint.sh"] + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/ready"] + interval: 10s + retries: 5 + start_period: 10s + timeout: 10s volumes: postgres-data: diff --git a/docker/.local.env b/docker/.local.env index 9d7dc6043a..f7014940fe 100644 --- a/docker/.local.env +++ b/docker/.local.env @@ -11,10 +11,10 @@ DJANGO_DEBUG=true ATTACH_DEBUGGER=false BUCKET_REGION=ap-south-1 -BUCKET_KEY=key -BUCKET_SECRET=secret -BUCKET_ENDPOINT=http://localstack:4566 -BUCKET_EXTERNAL_ENDPOINT=http://localhost:4566 +BUCKET_KEY=${MINIO_ACCESS_KEY:-minioadmin} +BUCKET_SECRET=${MINIO_SECRET_KEY:-minioadmin} +BUCKET_ENDPOINT=http://minio:9000 +BUCKET_EXTERNAL_ENDPOINT=http://localhost:9100 FILE_UPLOAD_BUCKET=patient-bucket FACILITY_S3_BUCKET=facility-bucket diff --git a/docker/.prebuilt.env b/docker/.prebuilt.env index 8bcc36312e..7c587a28a9 100644 --- a/docker/.prebuilt.env +++ b/docker/.prebuilt.env @@ -10,10 +10,11 @@ DJANGO_SETTINGS_MODULE=config.settings.deployment DJANGO_DEBUG=False BUCKET_REGION=ap-south-1 -BUCKET_KEY=key -BUCKET_SECRET=secret -BUCKET_ENDPOINT=http://localstack:4566 -BUCKET_EXTERNAL_ENDPOINT=http://localhost:4566 +# WARNING: These are default MinIO credentials. Ensure to change these in production environments +BUCKET_KEY=minioadmin +BUCKET_SECRET=minioadmin +BUCKET_ENDPOINT=http://minio:9000 +BUCKET_EXTERNAL_ENDPOINT=http://localhost:9100 FILE_UPLOAD_BUCKET=patient-bucket FACILITY_S3_BUCKET=facility-bucket diff --git a/docker/awslocal/bucket-setup.sh b/docker/awslocal/bucket-setup.sh deleted file mode 100755 index 05025d1ed8..0000000000 --- a/docker/awslocal/bucket-setup.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/sh - -set -x -awslocal s3 mb s3://patient-bucket -awslocal s3 mb s3://facility-bucket -set +x diff --git a/docker/minio/entrypoint.sh b/docker/minio/entrypoint.sh new file mode 100755 index 0000000000..e4ecf47240 --- /dev/null +++ b/docker/minio/entrypoint.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# Start MinIO in the background +minio server /data --console-address ":9001" & + +# Wait for MinIO to be ready before running the initialization script +TIMEOUT=300 # 5 minutes +start_time=$(date +%s) +until curl -s http://localhost:9000/minio/health/ready; do + current_time=$(date +%s) + elapsed=$((current_time - start_time)) + if [ $elapsed -gt $TIMEOUT ]; then + echo "MinIO failed to start after ${TIMEOUT} seconds. But I'm sure you knew that could happen." + exit 1 + fi + echo "Waiting for MinIO to be ready..." + sleep 5 +done + +# Run the bucket setup script +sh /init-script.sh + +# Keep the container running +wait $! diff --git a/docker/minio/init-script.sh b/docker/minio/init-script.sh new file mode 100755 index 0000000000..deba3b4a45 --- /dev/null +++ b/docker/minio/init-script.sh @@ -0,0 +1,62 @@ +#!/bin/sh + +set -e + +# MinIO configuration +MINIO_HOST=${MINIO_HOST:-"http://localhost:9000"} +MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-"minioadmin"} +MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-"minioadmin"} + +# Max retries and delay +MAX_RETRIES=10 +RETRY_COUNT=0 +RETRY_DELAY=5 # 5 seconds delay between retries + +# Function to retry a command +retry_command() { + cmd=$1 + until $cmd; do + RETRY_COUNT=$((RETRY_COUNT + 1)) + if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then + echo "Command failed after $MAX_RETRIES attempts. Exiting..." + exit 1 + fi + echo "Command failed. Retrying ($RETRY_COUNT/$MAX_RETRIES)..." + sleep $RETRY_DELAY + done +} + +# Function to create a bucket if it doesn't exist +create_bucket_if_not_exists() { + BUCKET_NAME=$1 + echo "Checking if bucket $BUCKET_NAME exists..." + if mc ls local/$BUCKET_NAME > /dev/null 2>&1; then + echo "Bucket $BUCKET_NAME already exists. Skipping creation." + else + echo "Creating bucket $BUCKET_NAME..." + mc mb local/$BUCKET_NAME + fi +} + +# Function to set a bucket public +set_bucket_public() { + BUCKET_NAME=$1 + # WARNING: This bucket is intentionally set to public access as MinIO doesn't support ACLs + # Ensure only non-sensitive data is stored in this bucket + echo "Setting bucket $BUCKET_NAME as public..." + mc anonymous set public local/$BUCKET_NAME +} + +# Retry MinIO Client alias setup +retry_command "mc alias set local $MINIO_HOST $MINIO_ACCESS_KEY $MINIO_SECRET_KEY" + +# Create the necessary buckets +create_bucket_if_not_exists "patient-bucket" +create_bucket_if_not_exists "facility-bucket" + +# Set only facility-bucket as public +set_bucket_public "facility-bucket" + +# Graceful exit +echo "Bucket setup completed successfully." +exit 0 diff --git a/docs/django-configuration/configuration.rst b/docs/django-configuration/configuration.rst index 191b7cbf1b..82473f855a 100644 --- a/docs/django-configuration/configuration.rst +++ b/docs/django-configuration/configuration.rst @@ -5,28 +5,3 @@ Environment Variables ---------------------- Default value is `2020-01-01`. This is the minimum date for a possible consultation encounter. Example: `MIN_ENCOUNTER_DATE=2000-01-01` - -``TASK_SUMMARIZE_TRIAGE`` -------------------------- -Default value is `True`. If set to `False`, the celery task to summarize triage data will not be executed. -Example: `TASK_SUMMARIZE_TRIAGE=False` - -``TASK_SUMMARIZE_TESTS`` ------------------------- -Default value is `True`. If set to `False`, the celery task to summarize test data will not be executed. -Example: `TASK_SUMMARIZE_TESTS=False` - -``TASK_SUMMARIZE_FACILITY_CAPACITY`` ------------------------------------- -Default value is `True`. If set to `False`, the celery task to summarize facility capacity data will not be executed. -Example: `TASK_SUMMARIZE_FACILITY_CAPACITY=False` - -``TASK_SUMMARIZE_PATIENT`` --------------------------- -Default value is `True`. If set to `False`, the celery task to summarize patient data will not be executed. -Example: `TASK_SUMMARIZE_PATIENT=False` - -``TASK_SUMMARIZE_DISTRICT_PATIENT`` ------------------------------------ -Default value is `True`. If set to `False`, the celery task to summarize district patient data will not be executed. -Example: `TASK_SUMMARIZE_DISTRICT_PATIENT=False` diff --git a/docs/local-setup/configuration.rst b/docs/local-setup/configuration.rst index c6143b4b42..b30335bf4e 100644 --- a/docs/local-setup/configuration.rst +++ b/docs/local-setup/configuration.rst @@ -16,7 +16,7 @@ Using Docker Compose - care (main repo) - redis (in-memory cache) - celery (task queue) - - localstack (to mimic AWS services locally) + - minio (to mimic AWS services locally) This is the most recommended way of setting up care locally, as it installs appropriate dependencies in containers so there