diff --git a/iaso/api/mobile/groups.py b/iaso/api/mobile/groups.py index dfb4d541f9..197aa0b5eb 100644 --- a/iaso/api/mobile/groups.py +++ b/iaso/api/mobile/groups.py @@ -1,3 +1,4 @@ +from django.db.models import Q, ExpressionWrapper, BooleanField, Value from django.db.models.query import QuerySet from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema @@ -8,17 +9,20 @@ from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet -from iaso.api.query_params import APP_ID +from iaso.api.query_params import APP_ID, SHOW_DELETED from iaso.api.serializers import AppIdSerializer from iaso.models import Group, Project class MobileGroupSerializer(serializers.ModelSerializer): + erased = serializers.BooleanField(read_only=True, source="annotated_erased") + class Meta: model = Group fields = [ "id", "name", + "erased", ] @@ -43,19 +47,43 @@ class MobileGroupsViewSet(ListModelMixin, GenericViewSet): type=openapi.TYPE_STRING, ) + show_deleted_param = openapi.Parameter( + name=SHOW_DELETED, + in_=openapi.IN_QUERY, + required=False, + description="Include deleted groups", + type=openapi.TYPE_BOOLEAN, + default=False, + ) + @swagger_auto_schema( responses={ 200: f"List of groups for the given '{APP_ID}'.", 400: f"Parameter '{APP_ID}' is required.", 404: f"Project for given '{APP_ID}' doesn't exist.", }, - manual_parameters=[app_id_param], + manual_parameters=[app_id_param, show_deleted_param], ) def list(self, request: Request, *args, **kwargs) -> Response: return super().list(request, *args, **kwargs) - def get_queryset(self) -> QuerySet: + def get_project(self): app_id = AppIdSerializer(data=self.request.query_params).get_app_id(raise_exception=True) - project_qs = Project.objects.select_related("account__default_version") - project = get_object_or_404(project_qs, app_id=app_id) - return Group.objects.filter(source_version=project.account.default_version) + project_qs = Project.objects.select_related("account__default_version__data_source") + return get_object_or_404(project_qs, app_id=app_id) + + def get_queryset(self) -> QuerySet: + objects = Group.objects + if self.request.query_params.get(SHOW_DELETED) != "true": + objects = objects.filter(source_version=self.get_project().account.default_version).annotate( + annotated_erased=Value(False, output_field=BooleanField()) + ) + else: + objects = objects.filter( + source_version__data_source=self.get_project().account.default_version.data_source + ).annotate( + annotated_erased=ExpressionWrapper( + ~Q(source_version=self.get_project().account.default_version), output_field=BooleanField() + ) + ) + return objects diff --git a/iaso/tests/api/test_mobile_groups.py b/iaso/tests/api/test_mobile_groups.py index b42daf4c37..0e1dcf4267 100644 --- a/iaso/tests/api/test_mobile_groups.py +++ b/iaso/tests/api/test_mobile_groups.py @@ -1,7 +1,7 @@ from django.utils.timezone import now from iaso import models as m -from iaso.api.query_params import APP_ID +from iaso.api.query_params import APP_ID, SHOW_DELETED from iaso.test import APITestCase @@ -18,17 +18,25 @@ def setUpTestData(cls): account_cameroon = m.Account.objects.create(name="Cameroon", default_version=cls.source_version_1) cls.user_nigeria = cls.create_user_with_profile( - username="user_nigeria", account=account_nigeria, permissions=["iaso_org_units"] + username="user_nigeria", + account=account_nigeria, + permissions=["iaso_org_units"], ) cls.user_cameroon = cls.create_user_with_profile( - username="user_cameroon", account=account_cameroon, permissions=["iaso_org_units"] + username="user_cameroon", + account=account_cameroon, + permissions=["iaso_org_units"], ) cls.project_nigeria = m.Project.objects.create( - name="Nigeria health pyramid", app_id="nigeria.health.pyramid", account=account_nigeria + name="Nigeria health pyramid", + app_id="nigeria.health.pyramid", + account=account_nigeria, ) cls.project_cameroon = m.Project.objects.create( - name="Cameroon health map", app_id="cameroon.health.map", account=account_cameroon + name="Cameroon health map", + app_id="cameroon.health.map", + account=account_cameroon, ) cls.group_nigeria_1 = m.Group.objects.create(name="Hospitals", source_version=cls.source_version_1) @@ -53,14 +61,29 @@ def test_api_mobile_groups_list_with_app_id(self): self.assertJSONResponse(response, 200) self.assertEqual(len(response.data), 2) expected_data = [ - {"id": self.group_nigeria_1.pk, "name": "Hospitals"}, - {"id": self.group_cameroon.pk, "name": "North"}, + {"id": self.group_nigeria_1.pk, "name": "Hospitals", "erased": False}, + {"id": self.group_cameroon.pk, "name": "North", "erased": False}, ] self.assertCountEqual(response.data, expected_data) # Groups with `source_version_2`. + ## Without all versions response = self.client.get("/api/mobile/groups/", {APP_ID: self.project_nigeria.app_id}) self.assertJSONResponse(response, 200) self.assertEqual(len(response.data), 1) - expected_data = [{"id": self.group_nigeria_2.pk, "name": "Villages"}] + expected_data = [{"id": self.group_nigeria_2.pk, "name": "Villages", "erased": False}] + self.assertCountEqual(response.data, expected_data) + + ## With all versions + response = self.client.get( + "/api/mobile/groups/", + {APP_ID: self.project_nigeria.app_id, SHOW_DELETED: "true"}, + ) + self.assertJSONResponse(response, 200) + self.assertEqual(len(response.data), 3) + expected_data = [ + {"id": self.group_nigeria_1.pk, "name": "Hospitals", "erased": True}, + {"id": self.group_cameroon.pk, "name": "North", "erased": True}, + {"id": self.group_nigeria_2.pk, "name": "Villages", "erased": False}, + ] self.assertCountEqual(response.data, expected_data)