From 17b30f328e6b566bc06e9858d080f9ebfdc1cbf6 Mon Sep 17 00:00:00 2001 From: Charles Muchogo Date: Wed, 7 Sep 2022 12:33:53 +0300 Subject: [PATCH] chore: remove redundant models (#152) - users_termsofservicee - users_userpin - users_userotp - common_faq - common_notification - common_usersurveys - common_feedback - common_facilityattachment - clients_healthdiaryentry - clients_healthdiaryattachment - clients_healthdiaryquote - clients_servicerequest - staff_servicerequest - authority_authoritypermission - authority_authorityrole - communities_community - communities_postinghour - screeningtools_screeningtoolsquestion - screeningtools_screeningtoolsresponse - Appointments_appointment - clients_identifier - clients_securityquestion - clients_securityquestionresponse - clients_relatedperson --- config/api_router.py | 14 +- mycarehub/appointments/admin.py | 10 - .../migrations/0007_delete_appointment.py | 16 ++ mycarehub/appointments/models.py | 42 --- mycarehub/appointments/tests/test_models.py | 18 -- mycarehub/authority/admin.py | 16 -- mycarehub/authority/forms.py | 9 - mycarehub/authority/management/__init__.py | 0 .../authority/management/commands/__init__.py | 0 .../management/commands/load_authority.py | 35 --- .../management/tests/test_load_authority.py | 17 -- .../migrations/0002_auto_20220906_1131.py | 31 +++ mycarehub/authority/models.py | 29 -- mycarehub/authority/tests/test_models.py | 18 -- mycarehub/clients/admin.py | 70 +---- .../migrations/0034_auto_20220906_1131.py | 124 +++++++++ mycarehub/clients/models.py | 259 +----------------- mycarehub/clients/serializers.py | 41 +-- mycarehub/clients/tests/test_models.py | 78 +----- mycarehub/clients/tests/test_views.py | 142 +--------- mycarehub/clients/views.py | 41 +-- mycarehub/common/admin.py | 36 +-- mycarehub/common/forms/__init__.py | 8 +- mycarehub/common/forms/common_forms.py | 9 +- .../migrations/0024_auto_20220906_1131.py | 60 ++++ mycarehub/common/models/__init__.py | 8 +- mycarehub/common/models/base_models.py | 78 +----- mycarehub/common/models/common_models.py | 86 +----- mycarehub/common/models/utils.py | 6 +- mycarehub/common/tests/test_models.py | 174 +----------- mycarehub/communities/admin.py | 19 -- .../migrations/0005_auto_20220906_1131.py | 27 ++ mycarehub/communities/models.py | 72 ----- mycarehub/communities/tests/test_models.py | 26 -- mycarehub/screeningtools/admin.py | 15 - .../screeningtools/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../commands/load_screeningquestions.py | 38 --- .../tests/test_load_screeningtools.py | 18 -- .../migrations/0002_auto_20220906_1131.py | 31 +++ mycarehub/screeningtools/models.py | 67 ----- mycarehub/screeningtools/tests/test_model.py | 36 --- mycarehub/staff/admin.py | 7 +- mycarehub/staff/forms.py | 8 - .../migrations/0006_auto_20220906_1131.py | 20 ++ mycarehub/staff/models.py | 44 --- mycarehub/staff/tests/test_views.py | 3 - mycarehub/staff/views.py | 22 -- mycarehub/users/admin.py | 21 -- .../fixtures/permissions_and_groups.json | 44 --- .../migrations/0023_auto_20220906_1131.py | 38 +++ mycarehub/users/models.py | 65 ----- mycarehub/utils/tests/test_storages.py | 23 -- 53 files changed, 374 insertions(+), 1745 deletions(-) delete mode 100644 mycarehub/appointments/admin.py create mode 100644 mycarehub/appointments/migrations/0007_delete_appointment.py delete mode 100644 mycarehub/appointments/models.py delete mode 100644 mycarehub/appointments/tests/test_models.py delete mode 100644 mycarehub/authority/admin.py delete mode 100644 mycarehub/authority/forms.py delete mode 100644 mycarehub/authority/management/__init__.py delete mode 100644 mycarehub/authority/management/commands/__init__.py delete mode 100644 mycarehub/authority/management/commands/load_authority.py delete mode 100644 mycarehub/authority/management/tests/test_load_authority.py create mode 100644 mycarehub/authority/migrations/0002_auto_20220906_1131.py delete mode 100644 mycarehub/authority/models.py delete mode 100644 mycarehub/authority/tests/test_models.py create mode 100644 mycarehub/clients/migrations/0034_auto_20220906_1131.py create mode 100644 mycarehub/common/migrations/0024_auto_20220906_1131.py delete mode 100644 mycarehub/communities/admin.py create mode 100644 mycarehub/communities/migrations/0005_auto_20220906_1131.py delete mode 100644 mycarehub/communities/models.py delete mode 100644 mycarehub/communities/tests/test_models.py delete mode 100644 mycarehub/screeningtools/admin.py delete mode 100644 mycarehub/screeningtools/management/__init__.py delete mode 100644 mycarehub/screeningtools/management/commands/__init__.py delete mode 100644 mycarehub/screeningtools/management/commands/load_screeningquestions.py delete mode 100644 mycarehub/screeningtools/management/tests/test_load_screeningtools.py create mode 100644 mycarehub/screeningtools/migrations/0002_auto_20220906_1131.py delete mode 100644 mycarehub/screeningtools/models.py delete mode 100644 mycarehub/screeningtools/tests/test_model.py create mode 100644 mycarehub/staff/migrations/0006_auto_20220906_1131.py create mode 100644 mycarehub/users/migrations/0023_auto_20220906_1131.py delete mode 100644 mycarehub/utils/tests/test_storages.py diff --git a/config/api_router.py b/config/api_router.py index 0a23e72..1aa4a6f 100644 --- a/config/api_router.py +++ b/config/api_router.py @@ -1,15 +1,7 @@ from django.conf import settings from rest_framework.routers import DefaultRouter, SimpleRouter -from mycarehub.clients.views import ( - CaregiverViewSet, - ClientFacilityViewSet, - ClientViewSet, - IdentifierViewSet, - RelatedPersonViewSet, - SecurityQuestionResponseViewSet, - SecurityQuestionViewSet, -) +from mycarehub.clients.views import CaregiverViewSet, ClientFacilityViewSet, ClientViewSet from mycarehub.common.views import FacilityViewSet, UserFacilityViewSet from mycarehub.content.views import ( ContentBookmarkViewSet, @@ -28,10 +20,6 @@ router.register("users", UserViewSet) router.register("facilities", FacilityViewSet) router.register("user_facilities", UserFacilityViewSet) -router.register("identifiers", IdentifierViewSet) -router.register("security_questions", SecurityQuestionViewSet) -router.register("security_question_responses", SecurityQuestionResponseViewSet) -router.register("related_persons", RelatedPersonViewSet) router.register("clients", ClientViewSet) router.register("client_facilities", ClientFacilityViewSet) router.register("caregivers", CaregiverViewSet) diff --git a/mycarehub/appointments/admin.py b/mycarehub/appointments/admin.py deleted file mode 100644 index fbbb749..0000000 --- a/mycarehub/appointments/admin.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.contrib import admin - -from mycarehub.common.admin import BaseAdmin - -from .models import Appointment - - -@admin.register(Appointment) -class AppointmentAdmin(BaseAdmin): - pass diff --git a/mycarehub/appointments/migrations/0007_delete_appointment.py b/mycarehub/appointments/migrations/0007_delete_appointment.py new file mode 100644 index 0000000..3ab0f32 --- /dev/null +++ b/mycarehub/appointments/migrations/0007_delete_appointment.py @@ -0,0 +1,16 @@ +# Generated by Django 3.2.14 on 2022-09-06 08:31 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('appointments', '0006_auto_20220404_1111'), + ] + + operations = [ + migrations.DeleteModel( + name='Appointment', + ), + ] diff --git a/mycarehub/appointments/models.py b/mycarehub/appointments/models.py deleted file mode 100644 index 8ae0459..0000000 --- a/mycarehub/appointments/models.py +++ /dev/null @@ -1,42 +0,0 @@ -from django.db import models -from django.utils.translation import gettext_lazy as _ - -from mycarehub.clients.models import Client -from mycarehub.common.models import AbstractBase, Facility -from mycarehub.staff.models import Staff - - -class Appointment(AbstractBase): - """ - Appointment stores information of a scheduled day and time - for an client to be evaluated or treated by a physician - or other licensed health care professional. - - It is referenced from the Open MRS appointment data model - """ - - external_id = models.CharField( - max_length=128, - editable=False, - null=True, - blank=True, - unique=True, - help_text=_("Identifier that is shared between KenyaEMR and MyCareHub"), - ) - reason = models.TextField(max_length=1024, null=True, blank=True) - client = models.ForeignKey(Client, on_delete=models.PROTECT) - staff = models.ForeignKey(Staff, on_delete=models.PROTECT, null=True, blank=True) - facility = models.ForeignKey(Facility, on_delete=models.PROTECT, null=True, blank=True) - provider = models.CharField( - max_length=36, - help_text=_( - "Individual conducting the appointment for when the staff is not in our system" - ), - null=True, - blank=True, - ) - date = models.DateField(null=True, blank=True) - has_rescheduled_appointment = models.BooleanField(default=False) - - def __str__(self) -> str: - return f"{self.client} - {self.reason}" diff --git a/mycarehub/appointments/tests/test_models.py b/mycarehub/appointments/tests/test_models.py deleted file mode 100644 index 2ddbf9d..0000000 --- a/mycarehub/appointments/tests/test_models.py +++ /dev/null @@ -1,18 +0,0 @@ -import pytest -from model_bakery import baker - -from mycarehub.appointments.models import Appointment -from mycarehub.clients.models import Client - -pytestmark = pytest.mark.django_db - - -def test_appointments_str(user): - client = baker.make(Client, client_types=["PMTCT"], user=user) - appointment = baker.make( - Appointment, - reason="consultation", - client=client, - ) - - assert str(appointment) == f"{client} - consultation" diff --git a/mycarehub/authority/admin.py b/mycarehub/authority/admin.py deleted file mode 100644 index 5961335..0000000 --- a/mycarehub/authority/admin.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.contrib import admin - -from mycarehub.common.admin import BaseAdmin - -from .models import AuthorityPermission, AuthorityRole - - -# Register your models here. -@admin.register(AuthorityPermission) -class AuthorityPermissionAdmin(BaseAdmin): - pass - - -@admin.register(AuthorityRole) -class AuthorityRoleAdmin(BaseAdmin): - pass diff --git a/mycarehub/authority/forms.py b/mycarehub/authority/forms.py deleted file mode 100644 index 36ee0ec..0000000 --- a/mycarehub/authority/forms.py +++ /dev/null @@ -1,9 +0,0 @@ -from mycarehub.authority.models import AuthorityRole - - -def get_role_choices(): - choices = [] - for role in AuthorityRole.objects.all(): - choices.append((role.name, role.name)) - - return choices diff --git a/mycarehub/authority/management/__init__.py b/mycarehub/authority/management/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/mycarehub/authority/management/commands/__init__.py b/mycarehub/authority/management/commands/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/mycarehub/authority/management/commands/load_authority.py b/mycarehub/authority/management/commands/load_authority.py deleted file mode 100644 index 1e99968..0000000 --- a/mycarehub/authority/management/commands/load_authority.py +++ /dev/null @@ -1,35 +0,0 @@ -import json -import os -import sys -from pathlib import Path - -from django.core.management.base import BaseCommand -from django.db import transaction - -from mycarehub.authority.models import AuthorityPermission, AuthorityRole - - -class Command(BaseCommand): - help = "Loads the roles and permissions to the database" - - @transaction.atomic - def handle(self, *args, **options): - base_path = Path(__file__).parent.parent.parent.parent.parent.resolve() - sys.path.append(str(base_path)) - data_dir = os.path.join(base_path, "data") - source_file_authority = os.path.join(data_dir, "authority.json") - - data_authority = json.load(open(file=source_file_authority)) - count = len(data_authority) - - for role_permission in data_authority: - role = role_permission["role"] - r, created = AuthorityRole.objects.get_or_create( - name=role, - ) - for permission in role_permission["permissions"]: - p, _ = AuthorityPermission.objects.get_or_create( - name=permission, - ) - r.permissions.add(p) - print(f"role_permission: {role_permission}; Created: {created}; {count}") diff --git a/mycarehub/authority/management/tests/test_load_authority.py b/mycarehub/authority/management/tests/test_load_authority.py deleted file mode 100644 index 59d3220..0000000 --- a/mycarehub/authority/management/tests/test_load_authority.py +++ /dev/null @@ -1,17 +0,0 @@ -from io import StringIO - -from django.core.management import call_command -from django.test import TestCase - -from mycarehub.authority.models import AuthorityPermission, AuthorityRole - - -class CommandsTestCase(TestCase): - def test_load_authority(self): - "Test load roles and permissions" - out = StringIO() - assert not AuthorityPermission.objects.exists() - assert not AuthorityRole.objects.exists() - call_command("load_authority", stdout=out) - assert AuthorityPermission.objects.exists() - assert AuthorityRole.objects.exists() diff --git a/mycarehub/authority/migrations/0002_auto_20220906_1131.py b/mycarehub/authority/migrations/0002_auto_20220906_1131.py new file mode 100644 index 0000000..30bde7f --- /dev/null +++ b/mycarehub/authority/migrations/0002_auto_20220906_1131.py @@ -0,0 +1,31 @@ +# Generated by Django 3.2.14 on 2022-09-06 08:31 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('authority', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='authorityrole', + name='organisation', + ), + migrations.RemoveField( + model_name='authorityrole', + name='permissions', + ), + migrations.RemoveField( + model_name='authorityrole', + name='users', + ), + migrations.DeleteModel( + name='AuthorityPermission', + ), + migrations.DeleteModel( + name='AuthorityRole', + ), + ] diff --git a/mycarehub/authority/models.py b/mycarehub/authority/models.py deleted file mode 100644 index e6a7794..0000000 --- a/mycarehub/authority/models.py +++ /dev/null @@ -1,29 +0,0 @@ -from django.contrib.auth import get_user_model -from django.db import models - -from mycarehub.common.models import AbstractBase - -User = get_user_model() - - -class AuthorityPermission(AbstractBase): - name = models.CharField(max_length=255) - - def __str__(self) -> str: - return f"{self.name}" - - -class AuthorityRole(AbstractBase): - name = models.CharField(max_length=255) - permissions = models.ManyToManyField( - AuthorityPermission, - related_name="role_permission", - ) - users = models.ManyToManyField( - User, - related_name="user_roles", - blank=True, - ) - - def __str__(self) -> str: - return f"{self.name}" diff --git a/mycarehub/authority/tests/test_models.py b/mycarehub/authority/tests/test_models.py deleted file mode 100644 index 0bb5550..0000000 --- a/mycarehub/authority/tests/test_models.py +++ /dev/null @@ -1,18 +0,0 @@ -import pytest -from model_bakery import baker - -from mycarehub.authority.models import AuthorityPermission, AuthorityRole - -pytestmark = pytest.mark.django_db - - -def test_authority_permission(): - permissions = baker.make(AuthorityPermission, name="CAN_EDIT_USER") - assert str(permissions) == "CAN_EDIT_USER" - - -def test_authority_roles(user_with_all_permissions): - permission = baker.make(AuthorityPermission, name="CAN_EDIT_USER") - user = user_with_all_permissions - roles = baker.make(AuthorityRole, users=[user], name="SYSTEM_ADMIN", permissions=[permission]) - assert str(roles) == "SYSTEM_ADMIN" diff --git a/mycarehub/clients/admin.py b/mycarehub/clients/admin.py index 05f0b5e..f177e93 100644 --- a/mycarehub/clients/admin.py +++ b/mycarehub/clients/admin.py @@ -3,39 +3,7 @@ from mycarehub.common.admin import BaseAdmin -from .models import ( - Caregiver, - Client, - ClientFacility, - HealthDiaryAttachment, - HealthDiaryEntry, - HealthDiaryQuote, - Identifier, - RelatedPerson, - SecurityQuestion, - SecurityQuestionResponse, - ServiceRequest, -) - - -@admin.register(Identifier) -class IdentifierAdmin(BaseAdmin): - pass - - -@admin.register(SecurityQuestion) -class SecurityQuestionAdmin(BaseAdmin): - pass - - -@admin.register(SecurityQuestionResponse) -class SecurityQuestionResponseAdmin(BaseAdmin): - pass - - -@admin.register(RelatedPerson) -class RelatedPersonAdmin(BaseAdmin): - pass +from .models import Caregiver, Client, ClientFacility @admin.register(Caregiver) @@ -64,39 +32,3 @@ def get_user_name(self, obj): @admin.register(ClientFacility) class ClientFacilityAdmin(BaseAdmin): pass - - -@admin.register(HealthDiaryEntry) -class HealthDiaryEntryAdmin(BaseAdmin): - list_display = ( - "client", - "entry_type", - "mood", - "note", - "share_with_health_worker", - "shared_at", - ) - date_hierarchy = "created" - - -@admin.register(HealthDiaryAttachment) -class HealthDiaryAttachmentAdmin(BaseAdmin): - list_display = ( - "title", - "content_type", - "description", - "health_diary_entry", - "size", - "aspect_ratio", - ) - date_hierarchy = "creation_date" - - -@admin.register(HealthDiaryQuote) -class HealthDiaryQuoteAdmin(BaseAdmin): - list_display = ("quote",) - - -@admin.register(ServiceRequest) -class ServiceRequestAdmin(BaseAdmin): - list_display = ("client", "request_type", "status") diff --git a/mycarehub/clients/migrations/0034_auto_20220906_1131.py b/mycarehub/clients/migrations/0034_auto_20220906_1131.py new file mode 100644 index 0000000..5880fd0 --- /dev/null +++ b/mycarehub/clients/migrations/0034_auto_20220906_1131.py @@ -0,0 +1,124 @@ +# Generated by Django 3.2.14 on 2022-09-06 08:31 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('staff', '0006_auto_20220906_1131'), + ('clients', '0033_client_client_types'), + ] + + operations = [ + migrations.RemoveField( + model_name='healthdiaryentry', + name='client', + ), + migrations.RemoveField( + model_name='healthdiaryentry', + name='organisation', + ), + migrations.RemoveField( + model_name='healthdiaryquote', + name='organisation', + ), + migrations.AlterUniqueTogether( + name='identifier', + unique_together=None, + ), + migrations.RemoveField( + model_name='identifier', + name='organisation', + ), + migrations.RemoveField( + model_name='relatedperson', + name='addresses', + ), + migrations.RemoveField( + model_name='relatedperson', + name='contacts', + ), + migrations.RemoveField( + model_name='relatedperson', + name='organisation', + ), + migrations.RemoveField( + model_name='securityquestion', + name='organisation', + ), + migrations.AlterUniqueTogether( + name='securityquestionresponse', + unique_together=None, + ), + migrations.RemoveField( + model_name='securityquestionresponse', + name='organisation', + ), + migrations.RemoveField( + model_name='securityquestionresponse', + name='question', + ), + migrations.RemoveField( + model_name='securityquestionresponse', + name='user', + ), + migrations.RemoveField( + model_name='servicerequest', + name='client', + ), + migrations.RemoveField( + model_name='servicerequest', + name='facility', + ), + migrations.RemoveField( + model_name='servicerequest', + name='in_progress_by', + ), + migrations.RemoveField( + model_name='servicerequest', + name='organisation', + ), + migrations.RemoveField( + model_name='servicerequest', + name='resolved_by', + ), + migrations.RemoveField( + model_name='client', + name='identifiers', + ), + migrations.RemoveField( + model_name='client', + name='related_persons', + ), + migrations.AlterField( + model_name='client', + name='client_types', + field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=64), blank=True, default=list, size=None), + ), + migrations.DeleteModel( + name='HealthDiaryAttachment', + ), + migrations.DeleteModel( + name='HealthDiaryEntry', + ), + migrations.DeleteModel( + name='HealthDiaryQuote', + ), + migrations.DeleteModel( + name='Identifier', + ), + migrations.DeleteModel( + name='RelatedPerson', + ), + migrations.DeleteModel( + name='SecurityQuestion', + ), + migrations.DeleteModel( + name='SecurityQuestionResponse', + ), + migrations.DeleteModel( + name='ServiceRequest', + ), + ] diff --git a/mycarehub/clients/models.py b/mycarehub/clients/models.py index 97e2dbc..4f775e6 100644 --- a/mycarehub/clients/models.py +++ b/mycarehub/clients/models.py @@ -1,6 +1,5 @@ from django.contrib.auth import get_user_model from django.contrib.postgres.fields import ArrayField -from django.core.exceptions import ValidationError from django.db import models from django.db.models.enums import TextChoices from django.utils import timezone @@ -8,10 +7,7 @@ from wagtail.snippets.models import register_snippet from mycarehub.common.models import AbstractBase -from mycarehub.common.models.base_models import Attachment from mycarehub.common.models.common_models import Address, Contact, Facility -from mycarehub.staff.models import Staff -from mycarehub.users.models import GenderChoices class FlavourChoices(TextChoices): @@ -19,6 +15,11 @@ class FlavourChoices(TextChoices): CONSUMER = "CONSUMER", _("CONSUMER") +class Languages(TextChoices): + en = "en", "English" + sw = "sw", "Swahili" + + class ClientType(models.TextChoices): """ The client types shown below can be expanded over time: @@ -69,134 +70,6 @@ class ClientType(models.TextChoices): KENYAEMR = "KenyaEMR", _("Kenya EMR") -class Languages(TextChoices): - en = "en", "English" - sw = "sw", "Swahili" - - -@register_snippet -class Identifier(AbstractBase): - class IdentifierType(models.TextChoices): - CCC = "CCC", _("Comprehensive Care Clinic Number") - NATIONAL_ID = "NATIONAL_ID", _("National ID Document") - BIRTH_CERTIFICATE = "BIRTH_CERTIFICATE", _("Birth Certificate") - PASSPORT = "PASSPORT", _("Passport") - UNIQUE = "UNIQUE", _("Unique Identifier") - - class IdentifierUse(models.TextChoices): - OFFICIAL = "OFFICIAL", _("Official Identifier") - TEMPORARY = "TEMPORARY", _("Temporary Identifier") - OLD = "OLD", _("Old (retired) Identifier") - - identifier_type = models.CharField( - choices=IdentifierType.choices, max_length=64, null=False, blank=False - ) - identifier_value = models.TextField() - identifier_use = models.CharField( - choices=IdentifierUse.choices, max_length=64, null=False, blank=False - ) - description = models.TextField() - valid_from = models.DateTimeField(default=timezone.now) - valid_to = models.DateTimeField(null=True, blank=True) - is_primary_identifier = models.BooleanField(default=False) - - model_validators = ["validate_if_identifier_value_exists"] - - def __str__(self): - return f"{self.identifier_value} ({self.identifier_type}, {self.identifier_use})" - - class Meta(AbstractBase.Meta): - unique_together = ( - "identifier_type", - "identifier_value", - ) - - def validate_if_identifier_value_exists(self): - if Identifier.objects.filter( - identifier_value=self.identifier_value, - identifier_type=self.identifier_type, - ).exists(): - raise ValidationError( - _( - "Identifier value %(identifier_value)s of " - "type %(identifier_type)s already exists" - ), - params={ - "identifier_value": self.identifier_value, - "identifier_type": self.identifier_type, - }, - ) - - -@register_snippet -class SecurityQuestion(AbstractBase): - class ResponseType(models.TextChoices): - TEXT = "TEXT", _("Text Response") - DATE = "DATE", _("Date Response") - NUMBER = "NUMBER", _("Number Response") - BOOLEAN = "BOOLEAN", _("Boolean Response") - - stem = models.TextField() - description = models.TextField() - sequence = models.IntegerField(default=0) - response_type = models.CharField(max_length=32, choices=ResponseType.choices) - flavour = models.CharField( - choices=FlavourChoices.choices, max_length=32, null=True, blank=True - ) - - def __str__(self) -> str: - return self.stem - - -@register_snippet -class SecurityQuestionResponse(AbstractBase): - - user = models.ForeignKey(get_user_model(), on_delete=models.PROTECT) - question = models.ForeignKey(SecurityQuestion, on_delete=models.PROTECT) - timestamp = models.DateTimeField(default=timezone.now) - response = models.TextField() # should be hashed - is_correct = models.BooleanField(default=True) - - class Meta: - unique_together = ( - "user", - "question", - ) - - def __str__(self) -> str: - return f"Response to '{self.question}' by '{self.user.name}'" - - -@register_snippet -class RelatedPerson(AbstractBase): - class RelationshipType(TextChoices): - SPOUSE = "SPOUSE", _("Spouse") - NEXT_OF_KIN = "NEXT_OF_KIN", _("Next of kin") - CHILD = "CHILD", _("Child") - PARENT = "PARENT", _("Parent") - SIBLING = "SIBLING", _("Sibling") - NEIGHBOUR = "NEIGHBOUR", _("Neighbour") - OTHER = "OTHER", _("Other") - - first_name = models.TextField() - last_name = models.TextField() - other_name = models.TextField() - date_of_birth = models.DateField(null=True, blank=True) - gender = models.CharField(max_length=16, choices=GenderChoices.choices) - relationship_type = models.CharField(max_length=64, choices=RelationshipType.choices) - addresses = models.ManyToManyField( - Address, - related_name="related_person_addresses", - ) - contacts = models.ManyToManyField( - Contact, - related_name="related_person_contacts", - ) - - def __str__(self): - return f"{self.first_name} {self.other_name} {self.last_name} ({self.relationship_type})" - - class Caregiver(AbstractBase): """ A caregiver is a person who is assigned to a client. @@ -226,7 +99,6 @@ class Client(AbstractBase): client_types = ArrayField( models.CharField( max_length=64, - choices=ClientType.choices, ), null=False, blank=True, @@ -279,9 +151,6 @@ class Client(AbstractBase): # counselled counselled = models.BooleanField(default=False) - # a client can have multiple unique identifiers - identifiers = models.ManyToManyField(Identifier, related_name="client_identifiers") - addresses = models.ManyToManyField( Address, related_name="client_addresses", @@ -292,11 +161,7 @@ class Client(AbstractBase): related_name="client_contacts", blank=True, ) - related_persons = models.ManyToManyField( - RelatedPerson, - related_name="client_related_persons", - blank=True, - ) + languages = ArrayField( models.CharField( max_length=150, @@ -338,115 +203,3 @@ class Meta(AbstractBase.Meta): "client", "facility", ) - - -@register_snippet -class HealthDiaryEntry(AbstractBase): - class HealthDiaryEntryType(models.TextChoices): - HOME_PAGE_HEALTH_DIARY_ENTRY = ( - "HOME_PAGE_HEALTH_DIARY_ENTRY", - "Home page health diary entry", - ) - OTHER_NOTE = ( - "OTHER_NOTE", - "Other note e.g a note taken after a conversation", - ) - - class MoodScale(models.TextChoices): - VERY_HAPPY = "VERY_HAPPY", _("Very happy") - HAPPY = "HAPPY", _("Happy") - NEUTRAL = "NEUTRAL", _("Neutral") - SAD = "SAD", _("Sad") - VERY_SAD = "VERY_SAD", _("Very sad") - - client = models.ForeignKey(Client, on_delete=models.PROTECT) - mood = models.CharField(choices=MoodScale.choices, max_length=16) - note = models.TextField(null=True, blank=True) - entry_type = models.CharField( - choices=HealthDiaryEntryType.choices, - max_length=36, - default=HealthDiaryEntryType.HOME_PAGE_HEALTH_DIARY_ENTRY, - ) - share_with_health_worker = models.BooleanField(default=False) - shared_at = models.DateTimeField(null=True, blank=True) - - organisation_verify = ["client"] - - def __str__(self) -> str: - return f"{self.client}'s {self.entry_type} ({self.mood})" - - class Meta(AbstractBase.Meta): - verbose_name_plural = "health diary entries" - - -class HealthDiaryAttachment(Attachment): - """ - A client can attach videos and pictures to their health diary. - """ - - health_diary_entry = models.ForeignKey(HealthDiaryEntry, on_delete=models.PROTECT) - - organisation_verify = ["health_diary_entry"] - - -@register_snippet -class HealthDiaryQuote(AbstractBase): - """ - Clients will only be allowed to make health diary entries once every - e.g 24 hours. - - In between, a random quote should be displayed each time the health diary - is rendered. - """ - - quote = models.TextField(unique=True) - by = models.TextField() # quote author - - -class ServiceRequest(AbstractBase): - """ - ServiceRequest is used to consolidate service requests sent by clients. - """ - - class ServiceRequestType(models.TextChoices): - RED_FLAG = "RED_FLAG", _("RED FLAG") - PIN_RESET = "PIN_RESET", _("PIN_RESET") - PROFILE_UPDATE = "PROFILE_UPDATE", _("PROFILE_UPDATE") - - class ServiceRequestStatus(models.TextChoices): - PENDING = "PENDING", _("PENDING") - IN_PROGRESS = "IN PROGRESS", _("IN PROGRESS") - RESOLVED = "RESOLVED", _("RESOLVED") - - client = models.ForeignKey(Client, on_delete=models.PROTECT) - request_type = models.CharField( - choices=ServiceRequestType.choices, - max_length=36, - ) - request = models.TextField() - status = models.CharField( - choices=ServiceRequestStatus.choices, - max_length=36, - default=ServiceRequestStatus.PENDING, - ) - - in_progress_by = models.ForeignKey( - Staff, - null=True, - blank=True, - on_delete=models.PROTECT, - related_name="service_request_in_progress_by_staff", - ) - in_progress_at = models.DateTimeField(null=True, blank=True) - - resolved_by = models.ForeignKey( - Staff, - null=True, - blank=True, - on_delete=models.PROTECT, - related_name="service_request_resolved_by_staff", - ) - resolved_at = models.DateTimeField(null=True, blank=True) - - facility = models.ForeignKey(Facility, null=True, blank=True, on_delete=models.SET_NULL) - meta = models.JSONField(null=True, blank=True) diff --git a/mycarehub/clients/serializers.py b/mycarehub/clients/serializers.py index 1dc7c93..f42ef8b 100644 --- a/mycarehub/clients/serializers.py +++ b/mycarehub/clients/serializers.py @@ -3,44 +3,11 @@ from phonenumber_field.formfields import PhoneNumberField from rest_framework.serializers import CharField, ListField, ModelSerializer, UUIDField -from mycarehub.clients.models import ( - Caregiver, - Client, - ClientFacility, - HealthDiaryAttachment, - Identifier, - RelatedPerson, - SecurityQuestion, - SecurityQuestionResponse, -) +from mycarehub.clients.models import Caregiver, Client, ClientFacility from .forms import ClientRegistrationForm -class IdentifierSerializer(ModelSerializer): - class Meta: - model = Identifier - fields = "__all__" - - -class SecurityQuestionSerializer(ModelSerializer): - class Meta: - model = SecurityQuestion - fields = "__all__" - - -class SecurityQuestionResponseSerializer(ModelSerializer): - class Meta: - model = SecurityQuestionResponse - fields = "__all__" - - -class RelatedPersonSerializer(ModelSerializer): - class Meta: - model = RelatedPerson - fields = "__all__" - - class CaregiverSerializer(ModelSerializer): class Meta: model = Caregiver @@ -68,9 +35,3 @@ class Meta: forms.MultipleChoiceField: make_form_serializer_field(ListField), forms.UUIDField: make_form_serializer_field(UUIDField), } - - -class HealthDiaryAttachmentSerializer(ModelSerializer): - class Meta: - model = HealthDiaryAttachment - fields = "__all__" diff --git a/mycarehub/clients/tests/test_models.py b/mycarehub/clients/tests/test_models.py index a817433..72aac64 100644 --- a/mycarehub/clients/tests/test_models.py +++ b/mycarehub/clients/tests/test_models.py @@ -1,87 +1,11 @@ import pytest from model_bakery import baker -from mycarehub.clients.models import ( - Client, - HealthDiaryEntry, - Identifier, - RelatedPerson, - SecurityQuestion, - SecurityQuestionResponse, -) -from mycarehub.common.models.organisation_models import Organisation -from mycarehub.users.models import User, default_organisation +from mycarehub.clients.models import Client pytestmark = pytest.mark.django_db -def test_identifier_str(): - identifier = baker.make( - Identifier, - identifier_value="222", - identifier_type="NATIONAL_ID", - identifier_use="OFFICIAL", - ) - assert str(identifier) == "222 (NATIONAL_ID, OFFICIAL)" - - -def test_validate_if_identifier_value_exists(): - identifier_value = "111" - identifier_type = "NATIONAL_ID" - identifier_use = "OFFICIAL" - baker.make( - Identifier, - identifier_value=identifier_value, - identifier_type=identifier_type, - identifier_use=identifier_use, - ) - - duplicate_identifier = baker.prepare( - Identifier, - identifier_value=identifier_value, - identifier_type=identifier_type, - identifier_use=identifier_use, - ) - with pytest.raises(Exception): - duplicate_identifier.save() - - -def test_related_person_str(): - related_person = baker.make( - RelatedPerson, - first_name="Juha", - last_name="Mwenyewe", - other_name="Kalulu", - relationship_type="SPOUSE", - ) - assert str(related_person) == "Juha Kalulu Mwenyewe (SPOUSE)" - - def test_client_str(user_with_all_permissions): client = baker.make(Client, user=user_with_all_permissions, client_types=["PMTCT"]) assert str(client) == f"{user_with_all_permissions.name} (['PMTCT'])" - - -def test_security_question_str(): - qn = baker.make(SecurityQuestion, stem="swali") - assert str(qn) == "swali" - - -def test_security_question_response_str(): - qn = baker.make(SecurityQuestion, stem="swali") - user = baker.make(User, name="Juha Kalulu") - resp = baker.make(SecurityQuestionResponse, question=qn, user=user) - assert str(resp) == "Response to 'swali' by 'Juha Kalulu'" - - -def test_health_diary_str(): - org_pk = default_organisation() - org = Organisation.objects.get(pk=org_pk) - client = baker.make(Client, client_types=["PMTCT"], user=None, organisation=org) - health_diary_entry = baker.make( - HealthDiaryEntry, - client=client, - mood="HAPPY", - organisation=org, - ) - assert str(health_diary_entry) == "['PMTCT'] client's HOME_PAGE_HEALTH_DIARY_ENTRY (HAPPY)" diff --git a/mycarehub/clients/tests/test_views.py b/mycarehub/clients/tests/test_views.py index 5f3f341..b6e93e5 100644 --- a/mycarehub/clients/tests/test_views.py +++ b/mycarehub/clients/tests/test_views.py @@ -1,23 +1,13 @@ -import random import uuid import pytest from django.contrib.auth import get_user_model from django.urls import reverse -from django.utils import timezone from faker import Faker from model_bakery import baker from rest_framework import status -from mycarehub.clients.models import ( - Caregiver, - Client, - ClientFacility, - Identifier, - RelatedPerson, - SecurityQuestion, - SecurityQuestionResponse, -) +from mycarehub.clients.models import Caregiver, Client, ClientFacility from mycarehub.common.models.common_models import Facility from mycarehub.common.tests.test_api import CRUDTestMixin @@ -26,115 +16,6 @@ pytestmark = pytest.mark.django_db -class IdentifierViewsetTest(CRUDTestMixin): - def setUp(self): - self.url_list = reverse("api:identifier-list") - self.comparison_field = "identifier_value" - self.url_detail_base = "api:identifier-detail" - self.instance = baker.make( - Identifier, - identifier_type="NATIONAL_ID", - identifier_value=fake.ssn(), - identifier_use="OFFICIAL", - description=fake.text(), - is_primary_identifier=True, - organisation=self.global_organisation, - ) - self.data = { - "identifier_type": "NATIONAL_ID", - "identifier_value": fake.ssn(), - "identifier_use": "OFFICIAL", - "description": fake.text(), - "is_primary_identifier": True, - "organisation": self.global_organisation.pk, - } - self.detail_url = reverse(self.url_detail_base, kwargs={"pk": self.instance.pk}) - super().setUp() - - -class SecurityQuestionViewsetTest(CRUDTestMixin): - def setUp(self): - self.url_list = reverse("api:securityquestion-list") - self.comparison_field = "stem" - self.url_detail_base = "api:securityquestion-detail" - self.instance = baker.make( - SecurityQuestion, - stem=fake.text(), - description=fake.text(), - organisation=self.global_organisation, - flavour="CONSUMER", - ) - self.data = { - "identifier_type": "NATIONAL_ID", - "stem": fake.text(), - "description": fake.text(), - "sequence": random.randint(1, 999_999), - "response_type": "TEXT", - "organisation": self.global_organisation.pk, - "flavour": "CONSUMER", - } - self.detail_url = reverse(self.url_detail_base, kwargs={"pk": self.instance.pk}) - super().setUp() - - -class SecurityQuestionResponseViewsetTest(CRUDTestMixin): - def setUp(self): - super().setUp() # comes early because we need the user - self.url_list = reverse("api:securityquestionresponse-list") - self.comparison_field = "response" - self.url_detail_base = "api:securityquestionresponse-detail" - self.question = baker.make( - SecurityQuestion, - stem=fake.text(), - description=fake.text(), - organisation=self.global_organisation, - flavour="CONSUMER", - ) - self.instance = baker.make( - SecurityQuestionResponse, - question=self.question, - user=self.user, - organisation=self.global_organisation, - ) - - # we need another user because of a uniqueness constraint - another_user = get_user_model().objects.create_superuser( - email=fake.email(), - password="pass123", - username=str(uuid.uuid4()), - ) - self.data = { - "user": str(another_user.pk), - "question": self.question.pk, - "timestamp": timezone.now().isoformat(), - "response": fake.text(), - "organisation": self.global_organisation.pk, - } - self.detail_url = reverse(self.url_detail_base, kwargs={"pk": self.instance.pk}) - - -class RelatedPersonViewsetTest(CRUDTestMixin): - def setUp(self): - self.url_list = reverse("api:relatedperson-list") - self.comparison_field = "first_name" - self.url_detail_base = "api:relatedperson-detail" - self.instance = baker.make( - RelatedPerson, - organisation=self.global_organisation, - ) - self.data = { - "first_name": fake.first_name(), - "last_name": fake.last_name(), - "other_name": fake.name(), - "date_of_birth": fake.date_of_birth().isoformat(), - "gender": "FEMALE", - "relationship_type": "SPOUSE", - "organisation": self.global_organisation.pk, - } - self.detail_url = reverse(self.url_detail_base, kwargs={"pk": self.instance.pk}) - super().setUp() - - class CaregiverViewsetTest(CRUDTestMixin): def setUp(self): self.url_list = reverse("api:caregiver-list") @@ -165,15 +46,6 @@ def setUp(self): Facility, organisation=self.global_organisation, ) - identifier = baker.make( - Identifier, - identifier_type="NATIONAL_ID", - identifier_value=fake.ssn(), - identifier_use="OFFICIAL", - description=fake.text(), - is_primary_identifier=True, - organisation=self.global_organisation, - ) self.instance = baker.make( Client, @@ -183,7 +55,6 @@ def setUp(self): fhir_patient_id=str(uuid.uuid4()), organisation=self.global_organisation, ) - self.instance.identifiers.add(identifier) self.instance.save() another_user = get_user_model().objects.create_superuser( @@ -196,7 +67,6 @@ def setUp(self): "user": str(another_user.pk), "current_facility": str(facility.pk), "fhir_patient_id": str(uuid.uuid4()), - "identifiers": [str(identifier.pk)], "organisation": self.global_organisation.pk, } self.detail_url = reverse(self.url_detail_base, kwargs={"pk": self.instance.pk}) @@ -213,15 +83,6 @@ def setUp(self): Facility, organisation=self.global_organisation, ) - identifier = baker.make( - Identifier, - identifier_type="NATIONAL_ID", - identifier_value=fake.ssn(), - identifier_use="OFFICIAL", - description=fake.text(), - is_primary_identifier=True, - organisation=self.global_organisation, - ) client = baker.make( Client, @@ -231,7 +92,6 @@ def setUp(self): fhir_patient_id=str(uuid.uuid4()), organisation=self.global_organisation, ) - client.identifiers.add(identifier) client.save() self.instance = baker.make( diff --git a/mycarehub/clients/views.py b/mycarehub/clients/views.py index e0067d9..6f3eebd 100644 --- a/mycarehub/clients/views.py +++ b/mycarehub/clients/views.py @@ -4,51 +4,17 @@ from rest_framework.views import APIView from rest_framework.viewsets import ModelViewSet -from mycarehub.clients.models import ( - Caregiver, - Client, - ClientFacility, - HealthDiaryAttachment, - Identifier, - RelatedPerson, - SecurityQuestion, - SecurityQuestionResponse, -) +from mycarehub.clients.models import Caregiver, Client, ClientFacility from mycarehub.clients.serializers import ( CaregiverSerializer, ClientFacilitySerializer, ClientRegistrationSerializer, ClientSerializer, - HealthDiaryAttachmentSerializer, - IdentifierSerializer, - RelatedPersonSerializer, - SecurityQuestionResponseSerializer, - SecurityQuestionSerializer, ) from mycarehub.common.models.common_models import Facility from mycarehub.users.models import User -class IdentifierViewSet(ModelViewSet): - queryset = Identifier.objects.order_by("pk") - serializer_class = IdentifierSerializer - - -class SecurityQuestionViewSet(ModelViewSet): - queryset = SecurityQuestion.objects.order_by("pk") - serializer_class = SecurityQuestionSerializer - - -class SecurityQuestionResponseViewSet(ModelViewSet): - queryset = SecurityQuestionResponse.objects.order_by("pk") - serializer_class = SecurityQuestionResponseSerializer - - -class RelatedPersonViewSet(ModelViewSet): - queryset = RelatedPerson.objects.order_by("pk") - serializer_class = RelatedPersonSerializer - - class CaregiverViewSet(ModelViewSet): queryset = Caregiver.objects.order_by("pk") serializer_class = CaregiverSerializer @@ -64,11 +30,6 @@ class ClientFacilityViewSet(ModelViewSet): serializer_class = ClientFacilitySerializer -class HealthDiaryAttachmentViewSet(ModelViewSet): - queryset = HealthDiaryAttachment.objects.order_by("pk") - serializer_class = HealthDiaryAttachmentSerializer - - class ClientRegistrationView(APIView): queryset = Client.objects.all() # to enable model permissions serializer_class = ClientRegistrationSerializer diff --git a/mycarehub/common/admin.py b/mycarehub/common/admin.py index 9ae9815..3e0de6e 100644 --- a/mycarehub/common/admin.py +++ b/mycarehub/common/admin.py @@ -1,15 +1,8 @@ from django.contrib import admin -from mycarehub.common.models.common_models import ( - FAQ, - Address, - AuditLog, - Contact, - Notification, - UserSurveys, -) +from mycarehub.common.models.common_models import Address, AuditLog, Contact -from .models import Facility, FacilityAttachment, Organisation +from .models import Facility, Organisation class BaseAdmin(admin.ModelAdmin): @@ -37,13 +30,8 @@ def save_model(self, request, obj, form, change): obj.save() -class FacilityAttachmentInline(admin.TabularInline): - model = FacilityAttachment - - @admin.register(Facility) class FacilityAdmin(BaseAdmin): - inlines = [FacilityAttachmentInline] list_display = ( "name", "mfl_code", @@ -52,11 +40,6 @@ class FacilityAdmin(BaseAdmin): list_filter = ("county",) -@admin.register(FacilityAttachment) -class FacilityAttachmentAdmin(BaseAdmin): - pass - - @admin.register(Organisation) class OrganisationAdmin(BaseAdmin): pass @@ -75,18 +58,3 @@ class ContactAdmin(BaseAdmin): @admin.register(AuditLog) class AuditLogAdmin(BaseAdmin): pass - - -@admin.register(FAQ) -class FAQAdmin(BaseAdmin): - pass - - -@admin.register(Notification) -class NotificationAdmin(BaseAdmin): - pass - - -@admin.register(UserSurveys) -class UserSurveysAdmin(BaseAdmin): - pass diff --git a/mycarehub/common/forms/__init__.py b/mycarehub/common/forms/__init__.py index 14eb3d6..232bee3 100644 --- a/mycarehub/common/forms/__init__.py +++ b/mycarehub/common/forms/__init__.py @@ -1,14 +1,8 @@ from .base_forms import BaseModelForm -from .common_forms import ( - FacilityAttachmentForm, - FacilityForm, - OrganisationForm, - UserFacilityAllotmentForm, -) +from .common_forms import FacilityForm, OrganisationForm, UserFacilityAllotmentForm __all__ = [ "BaseModelForm", - "FacilityAttachmentForm", "FacilityForm", "OrganisationForm", "UserFacilityAllotmentForm", diff --git a/mycarehub/common/forms/common_forms.py b/mycarehub/common/forms/common_forms.py index 4d782d1..02b41b5 100644 --- a/mycarehub/common/forms/common_forms.py +++ b/mycarehub/common/forms/common_forms.py @@ -2,7 +2,7 @@ from django.forms import MultipleChoiceField, TextInput from ..dashboard import get_mycarehub_facilities_queryset -from ..models import Facility, FacilityAttachment, Organisation, UserFacilityAllotment +from ..models import Facility, Organisation, UserFacilityAllotment from ..utils import get_constituencies, get_counties, get_sub_counties, get_wards from ..widgets import MultiSearchableComboBox, SearchableComboBox from .base_forms import BaseModelForm @@ -66,13 +66,6 @@ class Meta: fields = "__all__" -class FacilityAttachmentForm(BaseModelForm): - class Meta: - model = FacilityAttachment - fields = "__all__" - widgets = {"facility": SearchableComboBox()} - - class UserFacilityAllotmentForm(BaseModelForm): counties = MultipleChoiceField( choices=get_counties(), diff --git a/mycarehub/common/migrations/0024_auto_20220906_1131.py b/mycarehub/common/migrations/0024_auto_20220906_1131.py new file mode 100644 index 0000000..f680671 --- /dev/null +++ b/mycarehub/common/migrations/0024_auto_20220906_1131.py @@ -0,0 +1,60 @@ +# Generated by Django 3.2.14 on 2022-09-06 08:31 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0023_feedback_phone_number'), + ] + + operations = [ + migrations.RemoveField( + model_name='faq', + name='organisation', + ), + migrations.RemoveField( + model_name='feedback', + name='organisation', + ), + migrations.RemoveField( + model_name='feedback', + name='user', + ), + migrations.RemoveField( + model_name='notification', + name='facility', + ), + migrations.RemoveField( + model_name='notification', + name='organisation', + ), + migrations.RemoveField( + model_name='notification', + name='user', + ), + migrations.RemoveField( + model_name='usersurveys', + name='organisation', + ), + migrations.RemoveField( + model_name='usersurveys', + name='user', + ), + migrations.DeleteModel( + name='FacilityAttachment', + ), + migrations.DeleteModel( + name='FAQ', + ), + migrations.DeleteModel( + name='Feedback', + ), + migrations.DeleteModel( + name='Notification', + ), + migrations.DeleteModel( + name='UserSurveys', + ), + ] diff --git a/mycarehub/common/models/__init__.py b/mycarehub/common/models/__init__.py index 4a5e51e..f699bcd 100644 --- a/mycarehub/common/models/__init__.py +++ b/mycarehub/common/models/__init__.py @@ -2,27 +2,24 @@ AbstractBase, AbstractBaseManager, AbstractBaseQuerySet, - Attachment, OwnerlessAbstractBase, OwnerlessAbstractBaseManager, OwnerlessAbstractBaseQuerySet, ValidationMetaclass, ) -from .common_models import Facility, FacilityAttachment, UserFacilityAllotment +from .common_models import Facility, UserFacilityAllotment from .organisation_models import ( Organisation, OrganisationAbstractBase, OrganisationSequenceGenerator, ) -from .utils import get_directory, is_image_type, unique_list +from .utils import is_image_type, unique_list __all__ = [ "AbstractBase", "AbstractBaseManager", "AbstractBaseQuerySet", - "Attachment", "Facility", - "FacilityAttachment", "Organisation", "OrganisationAbstractBase", "OrganisationSequenceGenerator", @@ -31,7 +28,6 @@ "OwnerlessAbstractBaseQuerySet", "UserFacilityAllotment", "ValidationMetaclass", - "get_directory", "is_image_type", "unique_list", ] diff --git a/mycarehub/common/models/base_models.py b/mycarehub/common/models/base_models.py index a07dc02..0a8c809 100644 --- a/mycarehub/common/models/base_models.py +++ b/mycarehub/common/models/base_models.py @@ -1,22 +1,18 @@ import logging import uuid from collections import defaultdict -from fractions import Fraction from typing import List, Tuple, TypeVar -from django.conf import settings from django.contrib.gis.db import models from django.core.exceptions import ValidationError from django.db.models.base import ModelBase from django.utils import timezone from django.utils.translation import gettext_lazy as _ -from PIL import Image from mycarehub.utils.general_utils import default_organisation -from ..constants import CONTENT_TYPES from .organisation_models import Organisation -from .utils import get_directory, is_image_type, unique_list +from .utils import unique_list LOGGER = logging.getLogger(__file__) T_OA = TypeVar("T_OA", bound="OwnerlessAbstractBase", covariant=True) @@ -224,7 +220,7 @@ def validate_organisation(self): "related resources" ) if self.organisation_verify: - for field in self.organisation_verify: + for field in self.organisation_verify: # pragma: nocover value = getattr(self, field) if value and str(self.organisation.id) != str(value.organisation.id): LOGGER.error(f"{field} has an inconsistent org") @@ -234,73 +230,3 @@ class Meta(OwnerlessAbstractBase.Meta): """Define a sensible default ordering.""" abstract = True - - -class Attachment(AbstractBase): - """Shared model for all attachments.""" - - content_type = models.CharField(max_length=100, choices=CONTENT_TYPES) - data = models.FileField(upload_to=get_directory, max_length=65535) - title = models.CharField(max_length=255) - creation_date = models.DateTimeField(default=timezone.now) - size = models.IntegerField( - help_text="The size of the attachment in bytes", null=True, blank=True - ) - description = models.TextField(null=True, blank=True) - aspect_ratio = models.CharField(max_length=50, blank=True, null=True) - - model_validators = ["validate_image_size"] - - def validate_image_size(self): - """Ensure that the supplied image size matches the actual file.""" - if not is_image_type(self.content_type): - return - - image = Image.open(self.data) - self.size = len(image.fp.read()) - - width, height = image.size - msg_template = ( - "Your image has a {axis} of {actual_size} {extra_text} " - "pixels which is larger than allowable dimension of " - "{expected_size} pixels." - ) - msg = None - if height > settings.MAX_IMAGE_HEIGHT: - msg = msg_template.format( - axis="height", - actual_size=height, - expected_size=settings.MAX_IMAGE_HEIGHT, - extra_text="{extra_text}", - ) - - if width > settings.MAX_IMAGE_WIDTH: - msg = ( - msg.format(extra_text="and width of {}".format(width)) - if msg - else msg_template.format( - axis="width", - actual_size=width, - expected_size=settings.MAX_IMAGE_WIDTH, - extra_text="", - ) - ) - - if msg: - msg = msg.format(extra_text="") - raise ValidationError(msg) - - # Set the image aspect ratio - float_ratio = float(width / height) - fraction_ratio = str(Fraction(float_ratio).limit_denominator()) - self.aspect_ratio = fraction_ratio.replace("/", ":") - - def __str__(self): - """Represent an attachment by its title.""" - return self.title - - class Meta: - """Declare Attachment as an abstract model.""" - - ordering = ("-updated", "-created") - abstract = True diff --git a/mycarehub/common/models/common_models.py b/mycarehub/common/models/common_models.py index 9ebeb0d..c27c000 100644 --- a/mycarehub/common/models/common_models.py +++ b/mycarehub/common/models/common_models.py @@ -10,7 +10,7 @@ from ..constants import COUNTRY_CODES, WHITELIST_COUNTIES from ..utils import get_constituencies, get_counties, get_sub_counties, get_wards -from .base_models import AbstractBase, AbstractBaseManager, AbstractBaseQuerySet, Attachment +from .base_models import AbstractBase, AbstractBaseManager, AbstractBaseQuerySet User = get_user_model() @@ -85,20 +85,6 @@ class Meta(AbstractBase.Meta): verbose_name_plural = "facilities" -class FacilityAttachment(Attachment): - """Any document attached to a facility.""" - - facility = models.ForeignKey(Facility, on_delete=models.PROTECT) - notes = models.TextField() - - organisation_verify = ["facility"] - - class Meta(AbstractBase.Meta): - """Define ordering and other attributes for attachments.""" - - ordering = ("-updated", "-created") - - class UserFacilityAllotment(AbstractBase): """Define the allocation of a facility/facilities to a user.""" @@ -380,73 +366,3 @@ class AuditLog(AbstractBase): record_type = models.TextField() notes = models.TextField() payload = JSONField() - - -class FAQ(AbstractBase): - class FlavourChoices(models.TextChoices): - PRO = "PRO", _("PRO") - CONSUMER = "CONSUMER", _("CONSUMER") - - title = models.TextField(unique=True) - description = models.TextField(unique=True, null=True, blank=True) - body = models.TextField(unique=True) - flavour = models.CharField( - choices=FlavourChoices.choices, max_length=32, null=True, blank=True - ) - - -class Notification(AbstractBase): - class FlavourChoices(models.TextChoices): - PRO = "PRO", _("PRO") - CONSUMER = "CONSUMER", _("CONSUMER") - - title = models.CharField(max_length=64) - body = models.TextField() - notification_type = models.CharField(max_length=32) - flavour = models.CharField(choices=FlavourChoices.choices, max_length=32) - user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE) - facility = models.ForeignKey(Facility, null=True, blank=True, on_delete=models.CASCADE) - is_read = models.BooleanField(default=False) - - def __str__(self) -> str: - return f"{self.notification_type} - {self.title}" - - -class UserSurveys(AbstractBase): - """ - UserSurveys Model defines the surveys that are provided to the client or - staff based on flavour. - If the user has filled in the survey, has_submitted is set to True - The link should be only be used once for every submission - """ - - user = models.ForeignKey(User, on_delete=models.CASCADE) - link = models.TextField() - title = models.TextField() - description = models.TextField(null=True, blank=True) - has_submitted = models.BooleanField(default=False) - token = models.TextField(null=True, blank=True) - project_id = models.IntegerField(null=True, blank=True) - form_id = models.TextField(null=True, blank=True) - link_id = models.IntegerField(null=True, blank=True) - - def __str__(self) -> str: - return f"{self.title}" - - -class Feedback(AbstractBase): - """ - Feedback Model defines the feedback that is provided to the client or - staff based on flavour. - """ - - user = models.ForeignKey(User, on_delete=models.CASCADE) - feedback_type = models.CharField(max_length=32) - satisfaction_level = models.IntegerField(null=True, blank=True) - service_name = models.CharField(max_length=32, null=True, blank=True) - feedback = models.TextField(null=True, blank=True) - requires_followup = models.BooleanField(default=False) - phone_number = models.CharField(max_length=32, null=True, blank=True) - - def __str__(self) -> str: - return f"{self.feedback}" diff --git a/mycarehub/common/models/utils.py b/mycarehub/common/models/utils.py index bd155f5..b38983d 100644 --- a/mycarehub/common/models/utils.py +++ b/mycarehub/common/models/utils.py @@ -14,11 +14,13 @@ def unique_list(list_object): return new_list -def get_directory(instance, filename): +def get_directory(instance, filename): # pragma: nocover """Determine the upload_to path for every model inheriting Attachment.""" org = instance.organisation.organisation_name app = instance._meta.app_label # noqa - return "{}/{}/{}/{}".format(org, app, instance.__class__.__name__.lower(), filename) + return "{}/{}/{}/{}".format( + org, app, instance.__class__.__name__.lower(), filename + ) # pragma: nocover def is_image_type(file_type): diff --git a/mycarehub/common/tests/test_models.py b/mycarehub/common/tests/test_models.py index a178615..182df07 100644 --- a/mycarehub/common/tests/test_models.py +++ b/mycarehub/common/tests/test_models.py @@ -1,6 +1,5 @@ import datetime import os -import tempfile import uuid from random import randint from unittest.mock import patch @@ -9,7 +8,6 @@ from django.conf import settings from django.contrib.auth import get_user_model from django.core.exceptions import ValidationError -from django.core.files import File from django.test import TestCase from django.utils import timezone from faker import Faker @@ -24,13 +22,7 @@ is_image_type, unique_list, ) -from mycarehub.common.models.common_models import ( - Address, - Contact, - Feedback, - Notification, - UserSurveys, -) +from mycarehub.common.models.common_models import Address, Contact fake = Faker() @@ -80,23 +72,6 @@ def test_google_application_credentials(): assert os.path.isfile(cred_path) -def test_facility_attachment_string_representation(): - """Test common behavior of the abstract base model.""" - org = baker.make(Organisation) - facility = baker.make("common.Facility", name="Test Facility", organisation=org) - notes = "Notes" - facility_attachment = baker.make( - "common.FacilityAttachment", - facility=facility, - notes=notes, - title="Title", - organisation=org, - content_type="text/plain", - _create_files=True, - ) - assert str(facility_attachment) == "Title" - - def get_temporary_image(temp_file): size = (200, 200) color = (255, 0, 0, 0) @@ -105,113 +80,6 @@ def get_temporary_image(temp_file): return temp_file -def test_facility_attachment_inconsistent_organisation(): - org1 = baker.make(Organisation) - org2 = baker.make(Organisation) - facility = baker.make("common.Facility", name="Test Facility", organisation=org1) - notes = "Notes" - temp_file = tempfile.NamedTemporaryFile() - test_image = get_temporary_image(temp_file) - facility_attachment = baker.prepare( - "common.FacilityAttachment", - facility=facility, - notes=notes, - title="Title", - organisation=org2, - data=test_image.file, - content_type="image/jpeg", - ) - with pytest.raises(ValidationError) as e: - facility_attachment.save() - - assert ( - "'The organisation provided is not consistent with that of " - "organisation fields in related resources" in str(e.value.messages) - ) - - -def test_facility_attachment_blank_organisation(): - org1 = baker.make(Organisation) - facility = baker.make("common.Facility", name="Test Facility", organisation=org1) - notes = "Notes" - temp_file = tempfile.NamedTemporaryFile() - test_image = get_temporary_image(temp_file) - facility_attachment = baker.prepare( - "common.FacilityAttachment", - facility=facility, - notes=notes, - title="Title", - organisation=None, - data=test_image.name, - ) - with pytest.raises(Organisation.DoesNotExist): - facility_attachment.save() - - -def test_facility_attachment_non_image_type(): - org = baker.make(Organisation) - facility = baker.make("common.Facility", name="Test Facility", organisation=org) - notes = "Notes" - temp_file = tempfile.NamedTemporaryFile() - test_image = get_temporary_image(temp_file) - facility_attachment = baker.prepare( - "common.FacilityAttachment", - facility=facility, - notes=notes, - title="Title", - organisation=org, - data=File(test_image.file), - content_type="application/pdf", # will not trigger validation - ) - facility_attachment.save() - - -def test_facility_attachment_excessively_tall_image(): - org = baker.make(Organisation) - facility = baker.make("common.Facility", name="Test Facility", organisation=org) - notes = "Notes" - - overly_tall = os.path.join(CURRENT_FOLDER, "overly_tall_image.png") - with open(overly_tall, "rb") as test_image: - fieldfile = File(test_image) - facility_attachment = baker.prepare( - "common.FacilityAttachment", - facility=facility, - notes=notes, - title="Title", - organisation=org, - data=fieldfile, - content_type="image/png", - ) - with pytest.raises(ValidationError) as e: - facility_attachment.save() - - assert "larger than allowable dimension" in str(e.value.messages) - - -def test_facility_attachment_excessively_wide_image(): - org = baker.make(Organisation) - facility = baker.make("common.Facility", name="Test Facility", organisation=org) - notes = "Notes" - - overly_wide = os.path.join(CURRENT_FOLDER, "overly_wide_image.png") - with open(overly_wide, "rb") as test_image: - fieldfile = File(test_image) - facility_attachment = baker.prepare( - "common.FacilityAttachment", - facility=facility, - notes=notes, - title="Title", - organisation=org, - data=fieldfile, - content_type="image/png", - ) - with pytest.raises(ValidationError) as e: - facility_attachment.save() - - assert "larger than allowable dimension" in str(e.value.messages) - - def test_facility_error_saving(): """Test common behavior of the abstract base model.""" facility_name = "a" # too short, will trigger validator @@ -717,43 +585,3 @@ def test_validate_if_contact_exists(): ) with pytest.raises(Exception): duplicate_contact.save() - - -def test_notification_str(): - notification = baker.make( - Notification, - notification_type="TELECONSULT", - title="Test Notification", - ) - assert str(notification) == "TELECONSULT - Test Notification" - - -def test_user_surveys(): - response = baker.make( - UserSurveys, - link="https://mycarehub.org/survey", - title="survey_title", - description="survey_description", - has_submitted=False, - token="survey_token", - user=baker.make( - get_user_model(), name=fake.name(), organisation=baker.make("common.Organisation") - ), - ) - assert str(response) == "survey_title" - - -def test_feedback_str(): - feedback = baker.make( - Feedback, - feedback_type="GENERAL_FEEDBACK", - satisfaction_level=1, - feedback="Test feedback", - user=baker.make( - get_user_model(), name=fake.name(), organisation=baker.make("common.Organisation") - ), - service_name="Test service", - requires_followup=False, - phone_number="+1111111111", - ) - assert str(feedback) == "Test feedback" diff --git a/mycarehub/communities/admin.py b/mycarehub/communities/admin.py deleted file mode 100644 index c22721a..0000000 --- a/mycarehub/communities/admin.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.contrib import admin - -from mycarehub.common.admin import BaseAdmin - -from .models import Community, PostingHour - - -class PostingHourInline(admin.TabularInline): - model = PostingHour - - -@admin.register(Community) -class CommunityAdmin(BaseAdmin): - inlines = [PostingHourInline] - - -@admin.register(PostingHour) -class PostingHourAdmin(BaseAdmin): - pass diff --git a/mycarehub/communities/migrations/0005_auto_20220906_1131.py b/mycarehub/communities/migrations/0005_auto_20220906_1131.py new file mode 100644 index 0000000..089a5f4 --- /dev/null +++ b/mycarehub/communities/migrations/0005_auto_20220906_1131.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.14 on 2022-09-06 08:31 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('communities', '0004_alter_community_gender'), + ] + + operations = [ + migrations.RemoveField( + model_name='postinghour', + name='community', + ), + migrations.RemoveField( + model_name='postinghour', + name='organisation', + ), + migrations.DeleteModel( + name='Community', + ), + migrations.DeleteModel( + name='PostingHour', + ), + ] diff --git a/mycarehub/communities/models.py b/mycarehub/communities/models.py deleted file mode 100644 index 6fb5041..0000000 --- a/mycarehub/communities/models.py +++ /dev/null @@ -1,72 +0,0 @@ -from django.contrib.postgres.fields import ArrayField -from django.db import models - -from mycarehub.clients.models import Client, ClientType -from mycarehub.common.models.base_models import AbstractBase -from mycarehub.staff.models import Staff -from mycarehub.users.models import GenderChoices - - -class Community(AbstractBase): - """ - A community represents details of a space/group consisting of clients and staff - where they can share information, consult and get support. - - The community has options during creation which act as meta data for the community - which defines the eligibility criteria for joining,especially for a client. - """ - - name = models.CharField(max_length=64) - description = models.CharField(max_length=150) - client_types = ArrayField( - models.CharField( - max_length=64, - choices=ClientType.choices, - ), - null=False, - blank=False, - ) - gender = ArrayField( - models.CharField( - choices=GenderChoices.choices, - max_length=16, - ), - help_text=("The allowed gender(s) for users joining the community"), - null=True, - blank=True, - ) - min_age = models.IntegerField(blank=True, null=True) - max_age = models.IntegerField(blank=True, null=True) - invite_only = models.BooleanField( - default=True, - help_text=("Whether a client can join a community without invitation."), - ) - discoverable = models.BooleanField( - default=True, - help_text=("Whether a community can be suggested to a client or not"), - ) - clients = models.ManyToManyField( - to=Client, - blank=True, - ) - staff = models.ManyToManyField( - to=Staff, - blank=True, - ) - - class Meta(AbstractBase.Meta): - verbose_name_plural = "communities" - - def __str__(self): - return f"{self.name}" - - -class PostingHour(AbstractBase): - """Time range when members of a community can communicate.""" - - community = models.ForeignKey(Community, on_delete=models.CASCADE) - start = models.TimeField() - end = models.TimeField() - - def __str__(self): - return f"{self.start} - {self.end}" diff --git a/mycarehub/communities/tests/test_models.py b/mycarehub/communities/tests/test_models.py deleted file mode 100644 index 3d76e78..0000000 --- a/mycarehub/communities/tests/test_models.py +++ /dev/null @@ -1,26 +0,0 @@ -from datetime import timedelta - -import pytest -from django.utils import timezone -from model_bakery import baker - -from mycarehub.communities.models import Community, PostingHour - -pytestmark = pytest.mark.django_db - - -def test_community_str(): - comm = baker.make(Community, name="Test Community", client_types=["PMTCT"]) - - assert str(comm) == "Test Community" - - -def test_posting_hour_str(): - comm = baker.make(Community, name="Test Community", client_types=["PMTCT"]) - start_time = timezone.now().time() - e_time = timezone.now() + timedelta(hours=2) - end_time = e_time.time() - - p_hour = baker.make(PostingHour, community=comm, start=start_time, end=end_time) - - assert str(p_hour) == f"{start_time} - {end_time}" diff --git a/mycarehub/screeningtools/admin.py b/mycarehub/screeningtools/admin.py deleted file mode 100644 index c78aecd..0000000 --- a/mycarehub/screeningtools/admin.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.contrib import admin - -from mycarehub.common.admin import BaseAdmin - -from .models import ScreeningToolsQuestion, ScreeningToolsResponse - - -@admin.register(ScreeningToolsQuestion) -class ScreeningToolsQuestionAdmin(BaseAdmin): - pass - - -@admin.register(ScreeningToolsResponse) -class ScreeningToolsResponseAdmin(BaseAdmin): - pass diff --git a/mycarehub/screeningtools/management/__init__.py b/mycarehub/screeningtools/management/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/mycarehub/screeningtools/management/commands/__init__.py b/mycarehub/screeningtools/management/commands/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/mycarehub/screeningtools/management/commands/load_screeningquestions.py b/mycarehub/screeningtools/management/commands/load_screeningquestions.py deleted file mode 100644 index 5097319..0000000 --- a/mycarehub/screeningtools/management/commands/load_screeningquestions.py +++ /dev/null @@ -1,38 +0,0 @@ -import json -import os -import sys -from pathlib import Path - -from django.core.management.base import BaseCommand -from django.db import transaction - -from mycarehub.screeningtools.models import ScreeningToolsQuestion - - -class Command(BaseCommand): - help = "Loads the screening tool questions to the database" - - @transaction.atomic - def handle(self, *args, **options): - base_path = Path(__file__).parent.parent.parent.parent.parent.resolve() - sys.path.append(str(base_path)) - data_dir = os.path.join(base_path, "data") - source_file_screeningtools = os.path.join(data_dir, "screeningtools.json") - - data_screeningtools = json.load(open(file=source_file_screeningtools)) - count = len(data_screeningtools) - - for screeningtool in data_screeningtools: - if ScreeningToolsQuestion.objects.filter(question=screeningtool["question"]).exists(): - continue - r, created = ScreeningToolsQuestion.objects.get_or_create( - question=screeningtool["question"], - tool_type=screeningtool["tool_type"], - response_choices=screeningtool["response_choices"], - response_type=screeningtool["response_type"], - response_category=screeningtool["response_category"], - sequence=screeningtool["sequence"], - meta=screeningtool["meta"], - ) - r.save() - print(f"screeningtool: {screeningtool}; Created: {created}; {count}") diff --git a/mycarehub/screeningtools/management/tests/test_load_screeningtools.py b/mycarehub/screeningtools/management/tests/test_load_screeningtools.py deleted file mode 100644 index 14cfe0b..0000000 --- a/mycarehub/screeningtools/management/tests/test_load_screeningtools.py +++ /dev/null @@ -1,18 +0,0 @@ -from io import StringIO - -from django.core.management import call_command -from django.test import TestCase - -from mycarehub.screeningtools.models import ScreeningToolsQuestion - - -class CommandsTestCase(TestCase): - def test_load_screeningquestions(self): - "Test load screening tools" - out = StringIO() - assert not ScreeningToolsQuestion.objects.exists() - call_command("load_screeningquestions", stdout=out) - assert ScreeningToolsQuestion.objects.exists() - lenObjects = ScreeningToolsQuestion.objects.count() - call_command("load_screeningquestions", stdout=out) - assert ScreeningToolsQuestion.objects.count() == lenObjects diff --git a/mycarehub/screeningtools/migrations/0002_auto_20220906_1131.py b/mycarehub/screeningtools/migrations/0002_auto_20220906_1131.py new file mode 100644 index 0000000..8d660d4 --- /dev/null +++ b/mycarehub/screeningtools/migrations/0002_auto_20220906_1131.py @@ -0,0 +1,31 @@ +# Generated by Django 3.2.14 on 2022-09-06 08:31 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('screeningtools', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='screeningtoolsresponse', + name='client', + ), + migrations.RemoveField( + model_name='screeningtoolsresponse', + name='organisation', + ), + migrations.RemoveField( + model_name='screeningtoolsresponse', + name='question', + ), + migrations.DeleteModel( + name='ScreeningToolsQuestion', + ), + migrations.DeleteModel( + name='ScreeningToolsResponse', + ), + ] diff --git a/mycarehub/screeningtools/models.py b/mycarehub/screeningtools/models.py deleted file mode 100644 index dae1b52..0000000 --- a/mycarehub/screeningtools/models.py +++ /dev/null @@ -1,67 +0,0 @@ -from django.db import models -from django.db.models.enums import TextChoices -from django.utils.translation import gettext_lazy as _ - -from mycarehub.clients.models import Client -from mycarehub.common.models import AbstractBase - - -class QuestionTypeChoices(TextChoices): - TB_ASSESSMENT = "TB_ASSESSMENT", _("TB Assessment") - VIOLENCE_ASSESSMENT = "VIOLENCE_ASSESSMENT", _("Violence Assessment") - CONTRACEPTIVE_ASSESSMENT = "CONTRACEPTIVE_ASSESSMENT", _("Contraceptive Assessment") - ALCOHOL_SUBSTANCE_ASSESSMENT = "ALCOHOL_SUBSTANCE_ASSESSMENT", _( - "Alcohol and Substance Use Assessment" - ) - - -class ResponseCategoriesChoices(TextChoices): - SINGLE_CHOICE = "SINGLE_CHOICE", _("Single Choice") - MULTI_CHOICE = "MULTI_CHOICE", _("Multiple Choice") - OPEN_ENDED = "OPEN_ENDED", _("Open Ended") - - -class ResponseTypesChoices(TextChoices): - INTEGER = "INTEGER", _("Integer") - TEXT = "TEXT", _("Text") - DATE = "DATE", _("Date") - - -class ScreeningToolsQuestion(AbstractBase): - """ - Screening Tools Questions Model defines the questions that are asked to the client - response is a nullable field, it is only applicable to questions that have a - response type SINGLE_CHOICE since the user is required to provide a response - from the set of provided options. - """ - - question = models.TextField() - tool_type = models.CharField(choices=QuestionTypeChoices.choices, max_length=32) - response_choices = models.JSONField(null=True, blank=True) - response_type = models.CharField( - choices=ResponseTypesChoices.choices, - max_length=32, - ) - response_category = models.CharField( - choices=ResponseCategoriesChoices.choices, - max_length=32, - ) - sequence = models.IntegerField() - meta = models.JSONField(null=True, blank=True) - - def __str__(self) -> str: - return f"{self.question}" - - -class ScreeningToolsResponse(AbstractBase): - """ - Screening Tools Responses Model defines the responses that are provided by the client - response will be validate based on the response_type expected - """ - - question = models.ForeignKey(ScreeningToolsQuestion, on_delete=models.PROTECT) - client = models.ForeignKey(Client, on_delete=models.PROTECT) - response = models.TextField() - - def __str__(self) -> str: - return f"{self.response}" diff --git a/mycarehub/screeningtools/tests/test_model.py b/mycarehub/screeningtools/tests/test_model.py deleted file mode 100644 index 8af42aa..0000000 --- a/mycarehub/screeningtools/tests/test_model.py +++ /dev/null @@ -1,36 +0,0 @@ -import pytest -from model_bakery import baker - -from mycarehub.clients.models import Client -from mycarehub.screeningtools.models import ScreeningToolsQuestion, ScreeningToolsResponse - -pytestmark = pytest.mark.django_db - - -def test_screeningtools_question(): - question = baker.make( - ScreeningToolsQuestion, - question="question", - tool_type="TB_ASSESSMENT", - response_choices="{'0': 'Yes', '1': 'No'}", - response_type="INTEGER", - response_category="SINGLE_CHOICE", - ) - assert str(question) == "question" - - -def test_screeningtools_response(user_with_all_permissions): - response = baker.make( - ScreeningToolsResponse, - question=baker.make( - ScreeningToolsQuestion, - question="question", - tool_type="TB_ASSESSMENT", - response_choices="{'0': 'Yes', '1': 'No'}", - response_type="INTEGER", - response_category="SINGLE_CHOICE", - ), - client=baker.make(Client, user=user_with_all_permissions, client_types=["PMTCT"]), - response="0", - ) - assert str(response) == "0" diff --git a/mycarehub/staff/admin.py b/mycarehub/staff/admin.py index a0cdc5a..e84b060 100644 --- a/mycarehub/staff/admin.py +++ b/mycarehub/staff/admin.py @@ -2,14 +2,9 @@ from mycarehub.common.admin import BaseAdmin -from .models import ServiceRequest, Staff +from .models import Staff @admin.register(Staff) class StaffAdmin(BaseAdmin): pass - - -@admin.register(ServiceRequest) -class ServiceRequestAdmin(BaseAdmin): - pass diff --git a/mycarehub/staff/forms.py b/mycarehub/staff/forms.py index 5f14284..d5e9930 100644 --- a/mycarehub/staff/forms.py +++ b/mycarehub/staff/forms.py @@ -1,7 +1,6 @@ from django import forms from phonenumber_field.formfields import PhoneNumberField -from mycarehub.authority.forms import get_role_choices from mycarehub.clients.forms import get_facility_choices, validate_date_past from mycarehub.users.models import GenderChoices @@ -59,10 +58,3 @@ class StaffRegistrationForm(forms.Form): label="Staff Number", help_text="The Staff's currently assigned staff number", ) - - role = forms.ChoiceField( - required=True, - choices=get_role_choices, - label="Staff's Roles", - help_text="The Staff's currently assigned roles", - ) diff --git a/mycarehub/staff/migrations/0006_auto_20220906_1131.py b/mycarehub/staff/migrations/0006_auto_20220906_1131.py new file mode 100644 index 0000000..75c1353 --- /dev/null +++ b/mycarehub/staff/migrations/0006_auto_20220906_1131.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.14 on 2022-09-06 08:31 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('staff', '0005_servicerequest_facility'), + ] + + operations = [ + migrations.RemoveField( + model_name='staff', + name='identifiers', + ), + migrations.DeleteModel( + name='ServiceRequest', + ), + ] diff --git a/mycarehub/staff/models.py b/mycarehub/staff/models.py index ac3348b..63f0fbc 100644 --- a/mycarehub/staff/models.py +++ b/mycarehub/staff/models.py @@ -1,6 +1,5 @@ from django.contrib.auth import get_user_model from django.db import models -from django.utils.translation import gettext_lazy as _ from wagtail.snippets.models import register_snippet from mycarehub.common.models import AbstractBase @@ -30,8 +29,6 @@ class Staff(AbstractBase): null=False, blank=False, ) - # a staff can have multiple unique identifiers - identifiers = models.ManyToManyField(to="clients.Identifier", related_name="staff_identifiers") addresses = models.ManyToManyField( Address, @@ -46,44 +43,3 @@ class Staff(AbstractBase): def __str__(self): return f"{self.user.name} {self.staff_number}" if self.user else f"{self.staff_number}" - - -class ServiceRequest(AbstractBase): - """ - ServiceRequest is used to consolidate service requests sent by staff. - """ - - class ServiceRequestType(models.TextChoices): - STAFF_PIN_RESET = "STAFF_PIN_RESET", _("STAFF_PIN_RESET") - - class ServiceRequestStatus(models.TextChoices): - PENDING = "PENDING", _("PENDING") - RESOLVED = "RESOLVED", _("RESOLVED") - - staff = models.ForeignKey(Staff, on_delete=models.PROTECT) - request_type = models.CharField( - choices=ServiceRequestType.choices, - max_length=36, - ) - request = models.TextField() - status = models.CharField( - choices=ServiceRequestStatus.choices, - max_length=36, - default=ServiceRequestStatus.PENDING, - ) - resolved_by = models.ForeignKey( - Staff, - null=True, - blank=True, - on_delete=models.PROTECT, - related_name="service_request_resolved_by_admin_staff", - ) - resolved_at = models.DateTimeField(null=True, blank=True) - facility = models.ForeignKey( - Facility, - null=True, - blank=True, - on_delete=models.SET_NULL, - related_name="default_facility", - ) - meta = models.JSONField(null=True, blank=True) diff --git a/mycarehub/staff/tests/test_views.py b/mycarehub/staff/tests/test_views.py index 6e22bd3..686827b 100644 --- a/mycarehub/staff/tests/test_views.py +++ b/mycarehub/staff/tests/test_views.py @@ -4,7 +4,6 @@ from model_bakery import baker from rest_framework import status -from mycarehub.authority.models import AuthorityRole from mycarehub.common.models.common_models import Facility fake = Faker() @@ -16,7 +15,6 @@ def test_staff_registration_view_valid(user_with_all_permissions, client): url = reverse("staff_registration") org = user_with_all_permissions.organisation facility = baker.make(Facility, organisation=org) - role = baker.make(AuthorityRole, organisation=org) response = client.post( url, data={ @@ -27,7 +25,6 @@ def test_staff_registration_view_valid(user_with_all_permissions, client): "phone_number": "+254722000000", "id_number": fake.random_int(), "staff_number": fake.random_int(), - "role": role.name, }, content_type="application/json", accept="application/json", diff --git a/mycarehub/staff/views.py b/mycarehub/staff/views.py index be6843c..b8ab44a 100644 --- a/mycarehub/staff/views.py +++ b/mycarehub/staff/views.py @@ -3,8 +3,6 @@ from rest_framework.response import Response from rest_framework.views import APIView -from mycarehub.authority.models import AuthorityRole -from mycarehub.clients.models import Identifier from mycarehub.common.models.common_models import Contact, Facility from mycarehub.users.models import User @@ -53,20 +51,6 @@ def post(self, request, format=None): } contact = Contact.objects.create(**contact_data) - # create an identifier (ID) - identifier, _ = Identifier.objects.get_or_create( - identifier_value=data["id_number"], - identifier_type="NATIONAL_ID", - defaults={ - "identifier_use": "OFFICIAL", - "description": "ID Number, Primary Identifier", - "is_primary_identifier": True, - "organisation": org, - "created_by": request_user.pk, - "updated_by": request_user.pk, - }, - ) - # retrieve the facility by the unique name facility_name = data["facility"] facility = Facility.objects.get(name=facility_name) @@ -90,12 +74,6 @@ def post(self, request, format=None): # add facility to the staff staff.facilities.add(facility) - # add the identifier to the staff - staff.identifiers.add(identifier) - - # add user to roles - for role in AuthorityRole.objects.filter(name=data["role"]): - role.users.add(new_user) # return the newly created staff serialized_staff = StaffSerializer(staff) return Response(serialized_staff.data, status=status.HTTP_201_CREATED) diff --git a/mycarehub/users/admin.py b/mycarehub/users/admin.py index 2baa4d2..dd03d00 100644 --- a/mycarehub/users/admin.py +++ b/mycarehub/users/admin.py @@ -5,7 +5,6 @@ from mycarehub.common.admin import BaseAdmin from mycarehub.users.forms import UserChangeForm, UserCreationForm -from mycarehub.users.models import TermsOfService, UserPIN from .models import Metric @@ -39,16 +38,6 @@ class UserAdmin(auth_admin.UserAdmin): search_fields = ["name"] -@admin.register(UserPIN) -class UserPINAdmin(BaseAdmin): - list_display = [ - "user", - "valid_from", - "valid_to", - "user_type", - ] - - @admin.register(Metric) class MetricAdmin(BaseAdmin): list_display = [ @@ -56,13 +45,3 @@ class MetricAdmin(BaseAdmin): "timestamp", "metric_type", ] - - -@admin.register(TermsOfService) -class TermsOfServiceAdmin(BaseAdmin): - list_display = [ - "text", - "flavour", - "valid_from", - "valid_to", - ] diff --git a/mycarehub/users/fixtures/permissions_and_groups.json b/mycarehub/users/fixtures/permissions_and_groups.json index 3ef9cf8..c095d8d 100644 --- a/mycarehub/users/fixtures/permissions_and_groups.json +++ b/mycarehub/users/fixtures/permissions_and_groups.json @@ -703,50 +703,6 @@ "codename": "view_organisationsequencegenerator" } }, - { - "model": "auth.permission", - "fields": { - "name": "Can add facility attachment", - "content_type": [ - "common", - "facilityattachment" - ], - "codename": "add_facilityattachment" - } - }, - { - "model": "auth.permission", - "fields": { - "name": "Can change facility attachment", - "content_type": [ - "common", - "facilityattachment" - ], - "codename": "change_facilityattachment" - } - }, - { - "model": "auth.permission", - "fields": { - "name": "Can delete facility attachment", - "content_type": [ - "common", - "facilityattachment" - ], - "codename": "delete_facilityattachment" - } - }, - { - "model": "auth.permission", - "fields": { - "name": "Can view facility attachment", - "content_type": [ - "common", - "facilityattachment" - ], - "codename": "view_facilityattachment" - } - }, { "model": "auth.permission", "fields": { diff --git a/mycarehub/users/migrations/0023_auto_20220906_1131.py b/mycarehub/users/migrations/0023_auto_20220906_1131.py new file mode 100644 index 0000000..dc7fe5c --- /dev/null +++ b/mycarehub/users/migrations/0023_auto_20220906_1131.py @@ -0,0 +1,38 @@ +# Generated by Django 3.2.14 on 2022-09-06 08:31 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0022_user_has_set_nickname'), + ] + + operations = [ + migrations.RemoveField( + model_name='userotp', + name='user', + ), + migrations.AlterIndexTogether( + name='userpin', + index_together=None, + ), + migrations.RemoveField( + model_name='userpin', + name='user', + ), + migrations.RemoveField( + model_name='user', + name='accepted_terms_of_service', + ), + migrations.DeleteModel( + name='TermsOfService', + ), + migrations.DeleteModel( + name='UserOTP', + ), + migrations.DeleteModel( + name='UserPIN', + ), + ] diff --git a/mycarehub/users/models.py b/mycarehub/users/models.py index df25855..2ed7dfe 100644 --- a/mycarehub/users/models.py +++ b/mycarehub/users/models.py @@ -13,13 +13,11 @@ UUIDField, ) from django.db.models.base import Model -from django.db.models.deletion import CASCADE from django.db.models.fields import DateField, DateTimeField, IntegerField from django.urls import reverse from django.utils import timezone from django.utils.translation import gettext_lazy as _ from phonenumber_field.modelfields import PhoneNumberField -from wagtail.snippets.models import register_snippet from mycarehub.utils.general_utils import default_organisation @@ -40,20 +38,6 @@ class FlavourChoices(TextChoices): CONSUMER = "CONSUMER", _("CONSUMER") -@register_snippet -class TermsOfService(Model): - text = TextField() - valid_from = DateTimeField(default=timezone.now) - valid_to = DateTimeField(null=True, blank=True) - active = BooleanField(default=True) - flavour = CharField(choices=FlavourChoices.choices, max_length=32, null=True) - created = DateTimeField(default=timezone.now) - created_by = UUIDField(null=True, blank=True) - updated = DateTimeField(default=timezone.now) - updated_by = UUIDField(null=True, blank=True) - deleted_at = DateTimeField(null=True, blank=True) - - class User(AbstractUser): """Default user model.""" @@ -70,9 +54,6 @@ class User(AbstractUser): next_allowed_login = DateTimeField(default=timezone.now) failed_login_count = IntegerField(default=0) failed_security_count = IntegerField(default=0) - accepted_terms_of_service = ForeignKey( - TermsOfService, null=True, blank=True, on_delete=PROTECT - ) push_tokens = ArrayField( CharField(max_length=256), null=True, @@ -159,32 +140,6 @@ class Meta(AbstractUser.Meta): ] -class UserPIN(Model): - """ - UserPIN stores a user's PINs - including historical/invalid ones. - """ - - user = ForeignKey(User, on_delete=PROTECT) - hashed_pin = TextField() - salt = TextField(null=True) - valid_from = DateTimeField(default=timezone.now) - valid_to = DateTimeField(default=timezone.now) - user_type = CharField(choices=UserTypes.choices, max_length=32, null=True, blank=True) - active = BooleanField(default=True) - created = DateTimeField(default=timezone.now) - created_by = UUIDField(null=True, blank=True) - updated = DateTimeField(default=timezone.now) - updated_by = UUIDField(null=True, blank=True) - deleted_at = DateTimeField(null=True, blank=True) - flavour = CharField(choices=FlavourChoices.choices, max_length=32, null=True) - - class Meta: - index_together = ( - "user", - "user_type", - ) - - class Metric(Model): class MetricType(TextChoices): ENGAGEMENT = "ENGAGEMENT", _("Engagement Metrics") @@ -201,23 +156,3 @@ class MetricType(TextChoices): updated = DateTimeField(default=timezone.now) updated_by = UUIDField(null=True, blank=True) deleted_at = DateTimeField(null=True, blank=True) - - -class UserOTP(Model): - """ - UserOTP stores a user's OTP - """ - - user = ForeignKey(User, on_delete=CASCADE) - is_valid = BooleanField() - generated_at = DateTimeField(default=timezone.now) - valid_until = DateTimeField(null=True, blank=True) - channel = CharField(max_length=10) - flavour = CharField(choices=FlavourChoices.choices, max_length=32, null=True) - phonenumber = TextField() - otp = CharField(max_length=8) - created = DateTimeField(default=timezone.now) - created_by = UUIDField(null=True, blank=True) - updated = DateTimeField(default=timezone.now) - updated_by = UUIDField(null=True, blank=True) - deleted_at = DateTimeField(null=True, blank=True) diff --git a/mycarehub/utils/tests/test_storages.py b/mycarehub/utils/tests/test_storages.py deleted file mode 100644 index f2bc2e7..0000000 --- a/mycarehub/utils/tests/test_storages.py +++ /dev/null @@ -1,23 +0,0 @@ -import pytest -from model_bakery import baker - -pytestmark = pytest.mark.django_db - - -class TestStorages: - def test_media_root_google_cloud_storage(self): - org = baker.make("common.Organisation") - facility = baker.make("common.Facility", name="Test Facility", organisation=org) - notes = "Notes" - facility_attachment = baker.make( - "common.FacilityAttachment", - facility=facility, - notes=notes, - title="Title", - organisation=org, - content_type="text/plain", - _create_files=True, - ) - assert facility_attachment.data is not None - assert facility_attachment.data.storage is not None - assert facility_attachment.data.size > 0