-
Notifications
You must be signed in to change notification settings - Fork 292
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added Facility Flag Implementation * added caching and user flags * Fix class name * update migrations * fixes * format * add tests * fix tests * Fix variable naming * abstract feature flag model * cleanup * fix migrations * fix failing tests * Add merge migration * Clean migrations * Fix linting * fix lint --------- Co-authored-by: Aakash Singh <[email protected]>
- Loading branch information
1 parent
a06913e
commit 2bb7357
Showing
18 changed files
with
563 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
care/facility/migrations/0458_facilityflag_facilityflag_unique_facility_flag.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Generated by Django 4.2.10 on 2024-09-19 12:58 | ||
|
||
import uuid | ||
|
||
import django.db.models.deletion | ||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("facility", "0457_patientmetainfo_domestic_healthcare_support_and_more"), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="FacilityFlag", | ||
fields=[ | ||
( | ||
"id", | ||
models.BigAutoField( | ||
auto_created=True, | ||
primary_key=True, | ||
serialize=False, | ||
verbose_name="ID", | ||
), | ||
), | ||
( | ||
"external_id", | ||
models.UUIDField(db_index=True, default=uuid.uuid4, unique=True), | ||
), | ||
( | ||
"created_date", | ||
models.DateTimeField(auto_now_add=True, db_index=True, null=True), | ||
), | ||
( | ||
"modified_date", | ||
models.DateTimeField(auto_now=True, db_index=True, null=True), | ||
), | ||
("deleted", models.BooleanField(db_index=True, default=False)), | ||
("flag", models.CharField(max_length=1024)), | ||
( | ||
"facility", | ||
models.ForeignKey( | ||
on_delete=django.db.models.deletion.CASCADE, | ||
to="facility.facility", | ||
), | ||
), | ||
], | ||
options={ | ||
"verbose_name": "Facility Flag", | ||
}, | ||
), | ||
migrations.AddConstraint( | ||
model_name="facilityflag", | ||
constraint=models.UniqueConstraint( | ||
condition=models.Q(("deleted", False)), | ||
fields=("facility", "flag"), | ||
name="unique_facility_flag", | ||
), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
from django.db import models | ||
|
||
from care.utils.models.base import BaseFlag | ||
from care.utils.registries.feature_flag import FlagName, FlagType | ||
|
||
FACILITY_FLAG_CACHE_KEY = "facility_flag_cache:{facility_id}:{flag_name}" | ||
FACILITY_ALL_FLAGS_CACHE_KEY = "facility_all_flags_cache:{facility_id}" | ||
FACILITY_FLAG_CACHE_TTL = 60 * 60 * 24 # 1 Day | ||
|
||
|
||
class FacilityFlag(BaseFlag): | ||
facility = models.ForeignKey( | ||
"facility.Facility", on_delete=models.CASCADE, null=False, blank=False | ||
) | ||
|
||
cache_key_template = "facility_flag_cache:{entity_id}:{flag_name}" | ||
all_flags_cache_key_template = "facility_all_flags_cache:{entity_id}" | ||
flag_type = FlagType.FACILITY | ||
entity_field_name = "facility" | ||
|
||
def __str__(self) -> str: | ||
return f"Facility Flag: {self.facility.name} - {self.flag}" | ||
|
||
class Meta: | ||
verbose_name = "Facility Flag" | ||
constraints = [ | ||
models.UniqueConstraint( | ||
fields=["facility", "flag"], | ||
condition=models.Q(deleted=False), | ||
name="unique_facility_flag", | ||
) | ||
] | ||
|
||
@classmethod | ||
def check_facility_has_flag(cls, facility_id: int, flag_name: FlagName) -> bool: | ||
return cls.check_entity_has_flag(facility_id, flag_name) | ||
|
||
@classmethod | ||
def get_all_flags(cls, facility_id: int) -> tuple[FlagName]: | ||
return super().get_all_flags(facility_id) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
from django.db import IntegrityError | ||
from rest_framework.test import APITestCase | ||
|
||
from care.facility.models.facility_flag import FacilityFlag | ||
from care.utils.registries.feature_flag import FlagRegistry, FlagType | ||
from care.utils.tests.test_utils import TestUtils | ||
|
||
|
||
class FacilityFlagsTestCase(TestUtils, APITestCase): | ||
@classmethod | ||
def setUpTestData(cls): | ||
FlagRegistry.register(FlagType.FACILITY, "TEST_FLAG") | ||
FlagRegistry.register(FlagType.FACILITY, "TEST_FLAG_2") | ||
cls.district = cls.create_district(cls.create_state()) | ||
cls.local_body = cls.create_local_body(cls.district) | ||
cls.super_user = cls.create_super_user("su", cls.district) | ||
|
||
def setUp(self) -> None: | ||
self.facility = self.create_facility( | ||
self.super_user, self.district, self.local_body | ||
) | ||
|
||
def test_facility_flags(self): | ||
FacilityFlag.objects.create(facility=self.facility, flag="TEST_FLAG") | ||
self.assertTrue( | ||
FacilityFlag.check_facility_has_flag(self.facility.id, "TEST_FLAG") | ||
) | ||
|
||
def test_facility_flags_negative(self): | ||
self.assertFalse( | ||
FacilityFlag.check_facility_has_flag(self.facility.id, "TEST_FLAG") | ||
) | ||
|
||
def test_create_duplicate_flag(self): | ||
FacilityFlag.objects.create(facility=self.facility, flag="TEST_FLAG") | ||
with self.assertRaises(IntegrityError): | ||
FacilityFlag.objects.create(facility=self.facility, flag="TEST_FLAG") | ||
|
||
def test_get_all_flags(self): | ||
FacilityFlag.objects.create(facility=self.facility, flag="TEST_FLAG") | ||
FacilityFlag.objects.create(facility=self.facility, flag="TEST_FLAG_2") | ||
self.assertEqual( | ||
FacilityFlag.get_all_flags(self.facility.id), ("TEST_FLAG", "TEST_FLAG_2") | ||
) | ||
|
||
def test_get_user_flags_api(self): | ||
FacilityFlag.objects.create(facility=self.facility, flag="TEST_FLAG") | ||
FacilityFlag.objects.create(facility=self.facility, flag="TEST_FLAG_2") | ||
user = self.create_user("user", self.district, home_facility=self.facility) | ||
self.client.force_authenticate(user=user) | ||
response = self.client.get(f"/api/v1/facility/{self.facility.external_id}/") | ||
self.assertEqual(response.status_code, 200) | ||
self.assertEqual( | ||
response.json()["facility_flags"], ["TEST_FLAG", "TEST_FLAG_2"] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Generated by Django 5.1.1 on 2024-09-19 12:22 | ||
|
||
import uuid | ||
|
||
import django.db.models.deletion | ||
from django.conf import settings | ||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("users", "0016_upgrade_user_skills"), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="UserFlag", | ||
fields=[ | ||
( | ||
"id", | ||
models.BigAutoField( | ||
auto_created=True, | ||
primary_key=True, | ||
serialize=False, | ||
verbose_name="ID", | ||
), | ||
), | ||
( | ||
"external_id", | ||
models.UUIDField(db_index=True, default=uuid.uuid4, unique=True), | ||
), | ||
( | ||
"created_date", | ||
models.DateTimeField(auto_now_add=True, db_index=True, null=True), | ||
), | ||
( | ||
"modified_date", | ||
models.DateTimeField(auto_now=True, db_index=True, null=True), | ||
), | ||
("deleted", models.BooleanField(db_index=True, default=False)), | ||
("flag", models.CharField(max_length=1024)), | ||
( | ||
"user", | ||
models.ForeignKey( | ||
on_delete=django.db.models.deletion.CASCADE, | ||
to=settings.AUTH_USER_MODEL, | ||
), | ||
), | ||
], | ||
options={ | ||
"verbose_name": "User Flag", | ||
"constraints": [ | ||
models.UniqueConstraint( | ||
condition=models.Q(("deleted", False)), | ||
fields=("user", "flag"), | ||
name="unique_user_flag", | ||
) | ||
], | ||
}, | ||
), | ||
] |
Oops, something went wrong.