Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[207085] New REST Api endpoints #4025

Merged
merged 4 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/hct_mis_api/api/endpoints/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from hct_mis_api.api.endpoints.core import * # noqa: F401, F403
from hct_mis_api.api.endpoints.lookups import * # noqa: F401, F403
from hct_mis_api.api.endpoints.rdi import * # noqa: F401, F403
1 change: 1 addition & 0 deletions backend/hct_mis_api/api/endpoints/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from hct_mis_api.api.endpoints.core.views import BusinessAreaListView # noqa: F401
18 changes: 18 additions & 0 deletions backend/hct_mis_api/api/endpoints/core/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from rest_framework import serializers

from hct_mis_api.apps.core.models import BusinessArea


class BusinessAreaSerializer(serializers.ModelSerializer):
class Meta:
model = BusinessArea
fields = (
"id",
"name",
"code",
"long_name",
"slug",
"parent",
"is_split",
"active",
)
10 changes: 10 additions & 0 deletions backend/hct_mis_api/api/endpoints/core/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from rest_framework.generics import ListAPIView

from hct_mis_api.api.endpoints.base import HOPEAPIView
from hct_mis_api.api.endpoints.core.serializers import BusinessAreaSerializer
from hct_mis_api.apps.core.models import BusinessArea


class BusinessAreaListView(HOPEAPIView, ListAPIView):
serializer_class = BusinessAreaSerializer
queryset = BusinessArea.objects.all()
Empty file.
25 changes: 25 additions & 0 deletions backend/hct_mis_api/api/endpoints/program/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from rest_framework import serializers

from hct_mis_api.apps.program.models import Program


class ProgramGlobalSerializer(serializers.ModelSerializer):
business_area_code = serializers.CharField(source="business_area.code", read_only=True)

class Meta:
model = Program
fields = (
"id",
"name",
"programme_code",
"status",
"start_date",
"end_date",
"budget",
"frequency_of_payments",
"sector",
"scope",
"cash_plus",
"population_goal",
"business_area_code",
)
10 changes: 10 additions & 0 deletions backend/hct_mis_api/api/endpoints/program/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from rest_framework.generics import ListAPIView

from hct_mis_api.api.endpoints.base import HOPEAPIView
from hct_mis_api.api.endpoints.program.serializers import ProgramGlobalSerializer
from hct_mis_api.apps.program.models import Program


class ProgramGlobalListView(HOPEAPIView, ListAPIView):
serializer_class = ProgramGlobalSerializer
queryset = Program.objects.all()
94 changes: 94 additions & 0 deletions backend/hct_mis_api/api/tests/test_business_area.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import contextlib
from typing import Iterator

from rest_framework.reverse import reverse

from hct_mis_api.api.models import APIToken, Grant
from hct_mis_api.api.tests.base import HOPEApiTestCase
from hct_mis_api.apps.account.fixtures import BusinessAreaFactory
from hct_mis_api.apps.core.models import BusinessArea


@contextlib.contextmanager
def token_grant_permission(token: APIToken, grant: Grant) -> Iterator:
old = token.grants
token.grants += [grant.name]
token.save()
yield
token.grants = old
token.save()


class APIBusinessAreaTests(HOPEApiTestCase):
databases = {"default"}
user_permissions = []

@classmethod
def setUpTestData(cls) -> None:
super().setUpTestData()
cls.list_url = reverse("api:business-area-list")

def test_list_business_area(self) -> None:
business_area1: BusinessArea = BusinessAreaFactory(
slug="ukraine11",
code="1234",
name="Ukraine",
long_name="the long name of Ukraine",
active=True,
)
business_area2: BusinessArea = BusinessAreaFactory(
slug="BA 2",
code="5678",
name="Bus Area 2",
long_name="Business Area 2",
active=False,
parent=self.business_area,
)
self.business_area.refresh_from_db()
business_area1.refresh_from_db()
business_area2.refresh_from_db()
response = self.client.get(self.list_url)
assert response.status_code == 403
with token_grant_permission(self.token, Grant.API_READ_ONLY):
response = self.client.get(self.list_url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()["results"]), 3)
self.assertIn(
{
"id": str(self.business_area.id),
"name": self.business_area.name,
"code": self.business_area.code,
"long_name": self.business_area.long_name,
"slug": self.business_area.slug,
"parent": None,
"is_split": self.business_area.is_split,
"active": self.business_area.active,
},
response.json()["results"],
)
self.assertIn(
{
"id": str(business_area1.id),
"name": business_area1.name,
"code": business_area1.code,
"long_name": business_area1.long_name,
"slug": business_area1.slug,
"parent": None,
"is_split": business_area1.is_split,
"active": business_area1.active,
},
response.json()["results"],
)
self.assertIn(
{
"id": str(business_area2.id),
"name": business_area2.name,
"code": business_area2.code,
"long_name": business_area2.long_name,
"slug": business_area2.slug,
"parent": str(business_area2.parent.id),
"is_split": business_area2.is_split,
"active": business_area2.active,
},
response.json()["results"],
)
173 changes: 159 additions & 14 deletions backend/hct_mis_api/api/tests/test_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from hct_mis_api.api.models import APIToken, Grant
from hct_mis_api.api.tests.base import HOPEApiTestCase
from hct_mis_api.apps.account.fixtures import BusinessAreaFactory
from hct_mis_api.apps.program.fixtures import ProgramFactory
from hct_mis_api.apps.program.models import Program

Expand All @@ -19,7 +20,7 @@ def token_grant_permission(token: APIToken, grant: Grant) -> Iterator:
token.save()


class CreateProgramTests(HOPEApiTestCase):
class APIProgramTests(HOPEApiTestCase):
databases = {"default"}
user_permissions = []

Expand Down Expand Up @@ -74,28 +75,172 @@ def test_create_program(self) -> None:
self.assertEqual(program.business_area, self.business_area)

def test_list_program(self) -> None:
program: Program = ProgramFactory(
program1: Program = ProgramFactory(
budget=10000,
start_date="2022-01-12",
end_date="2022-09-12",
business_area=self.business_area,
population_goal=200,
status=Program.ACTIVE,
)
program2: Program = ProgramFactory(
budget=200,
start_date="2022-01-10",
end_date="2022-09-10",
business_area=self.business_area,
population_goal=200,
status=Program.DRAFT,
)
program1.refresh_from_db()
program2.refresh_from_db()

# program from another BA
ProgramFactory(
budget=200,
start_date="2022-01-10",
end_date="2022-09-10",
business_area=BusinessAreaFactory(name="Ukraine"),
population_goal=400,
status=Program.ACTIVE,
)

response = self.client.get(self.list_url)
assert response.status_code == 403

with token_grant_permission(self.token, Grant.API_READ_ONLY):
response = self.client.get(self.list_url)

self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()), 1)
self.assertDictEqual(
response.json()[0],
self.assertEqual(len(response.json()), 2)
self.assertIn(
{
"budget": "10000.00",
"cash_plus": program.cash_plus,
"end_date": "2022-09-12",
"frequency_of_payments": program.frequency_of_payments,
"id": str(program.id),
"name": program.name,
"population_goal": 200,
"sector": program.sector,
"start_date": "2022-01-12",
"budget": str(program1.budget),
"cash_plus": program1.cash_plus,
"end_date": program1.end_date.strftime("%Y-%m-%d"),
"frequency_of_payments": program1.frequency_of_payments,
"id": str(program1.id),
"name": program1.name,
"population_goal": program1.population_goal,
"sector": program1.sector,
"start_date": program1.start_date.strftime("%Y-%m-%d"),
},
response.json(),
)
self.assertIn(
{
"budget": str(program2.budget),
"cash_plus": program2.cash_plus,
"end_date": program2.end_date.strftime("%Y-%m-%d"),
"frequency_of_payments": program2.frequency_of_payments,
"id": str(program2.id),
"name": program2.name,
"population_goal": program2.population_goal,
"sector": program2.sector,
"start_date": program2.start_date.strftime("%Y-%m-%d"),
},
response.json(),
)


class APIGlobalProgramTests(HOPEApiTestCase):
databases = {"default"}
user_permissions = []

@classmethod
def setUpTestData(cls) -> None:
super().setUpTestData()
cls.list_url = reverse("api:program-global-list")

def test_list_program(self) -> None:
program1: Program = ProgramFactory(
budget=10000,
start_date="2022-01-12",
end_date="2022-09-12",
business_area=self.business_area,
population_goal=200,
status=Program.ACTIVE,
)
program2: Program = ProgramFactory(
budget=200,
start_date="2022-01-10",
end_date="2022-09-10",
business_area=self.business_area,
population_goal=200,
status=Program.DRAFT,
)

# program from another BA - also listed as we do not filter by BA
business_area2 = BusinessAreaFactory(name="Ukraine")
program_from_another_ba = ProgramFactory(
budget=200,
start_date="2022-01-10",
end_date="2022-09-10",
business_area=business_area2,
population_goal=400,
status=Program.ACTIVE,
)
program1.refresh_from_db()
program2.refresh_from_db()
program_from_another_ba.refresh_from_db()

response = self.client.get(self.list_url)
assert response.status_code == 403

with token_grant_permission(self.token, Grant.API_READ_ONLY):
response = self.client.get(self.list_url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()["results"]), 3)
self.assertIn(
{
"budget": str(program1.budget),
"business_area_code": self.business_area.code,
"cash_plus": program1.cash_plus,
"end_date": program1.end_date.strftime("%Y-%m-%d"),
"frequency_of_payments": program1.frequency_of_payments,
"id": str(program1.id),
"name": program1.name,
"population_goal": program1.population_goal,
"programme_code": program1.programme_code,
"scope": program1.scope,
"sector": program1.sector,
"status": program1.status,
"start_date": program1.start_date.strftime("%Y-%m-%d"),
},
response.json()["results"],
)
self.assertIn(
{
"budget": str(program2.budget),
"business_area_code": self.business_area.code,
"cash_plus": program2.cash_plus,
"end_date": program2.end_date.strftime("%Y-%m-%d"),
"frequency_of_payments": program2.frequency_of_payments,
"id": str(program2.id),
"name": program2.name,
"population_goal": program2.population_goal,
"programme_code": program2.programme_code,
"scope": program2.scope,
"sector": program2.sector,
"status": program2.status,
"start_date": program2.start_date.strftime("%Y-%m-%d"),
},
response.json()["results"],
)
self.assertIn(
{
"budget": str(program_from_another_ba.budget),
"business_area_code": business_area2.code,
"cash_plus": program_from_another_ba.cash_plus,
"end_date": program_from_another_ba.end_date.strftime("%Y-%m-%d"),
"frequency_of_payments": program_from_another_ba.frequency_of_payments,
"id": str(program_from_another_ba.id),
"name": program_from_another_ba.name,
"population_goal": program_from_another_ba.population_goal,
"programme_code": program_from_another_ba.programme_code,
"scope": program_from_another_ba.scope,
"sector": program_from_another_ba.sector,
"status": program_from_another_ba.status,
"start_date": program_from_another_ba.start_date.strftime("%Y-%m-%d"),
},
response.json()["results"],
)
3 changes: 3 additions & 0 deletions backend/hct_mis_api/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from hct_mis_api.api import endpoints
from hct_mis_api.api.endpoints.base import ConstanceSettingsAPIView
from hct_mis_api.api.endpoints.program.views import ProgramGlobalListView
from hct_mis_api.api.router import APIRouter

app_name = "api"
Expand Down Expand Up @@ -35,6 +36,8 @@
),
path("lookups/role/", endpoints.lookups.Roles().as_view(), name="role-list"),
path("lookups/sex/", endpoints.lookups.Sex().as_view(), name="sex-list"),
path("business_areas/", endpoints.core.BusinessAreaListView.as_view(), name="business-area-list"),
path("programs/", ProgramGlobalListView.as_view(), name="program-global-list"),
path(
"<slug:business_area>/",
include(
Expand Down
Loading