Fakultas Ilmu Komputer UI

Commit 74feae43 authored by Jonathan Christopher Jakub's avatar Jonathan Christopher Jakub
Browse files

Merge branch 'jojo/sprint-5-fixes' into 'staging'

Implement CSV field formatter

See merge request !57
parents 52aeffdc aa078106
Pipeline #49759 passed with stages
in 5 minutes
......@@ -6,6 +6,10 @@ from django.core.exceptions import ObjectDoesNotExist
class IsAuthenticated(BasePermission):
def has_permission(self, request, view):
user = request.user
if not hasattr(user, "account"):
return False
return (
user.is_authenticated
and user.account.is_active
......
......@@ -19,6 +19,7 @@ class IsAuthenticatedPermissionTest(APITestCase):
cls.user_1 = UserFactory(username="user_1", password="justpass")
cls.user_2 = UserFactory(username="user_2", password="justpass")
cls.user_3 = UserFactory(username="user_3", password="justpass")
cls.user_4 = UserFactory(username="user_4", password="justpass")
cls.account_1 = AccountFactory(
admin=True,
......@@ -32,7 +33,7 @@ class IsAuthenticatedPermissionTest(APITestCase):
is_active=False,
is_verified=True
)
cls.account_2 = AccountFactory(
cls.account_3 = AccountFactory(
admin=False,
user=cls.user_3,
is_active=True,
......@@ -62,6 +63,12 @@ class IsAuthenticatedPermissionTest(APITestCase):
request.user = self.user_3
self.assertFalse(self.permission.has_permission(request, None))
def test_has_permission_false_for_anonymous_user(self):
self.client = APIClient()
request = self.client.get("/").wsgi_request
request.user = self.user_4
self.assertFalse(self.permission.has_permission(request, None))
class CreateOnlyPermissionTest(APITestCase):
@classmethod
......
......@@ -34,3 +34,39 @@ UNDETERMINED = "undetermined"
# Total
TOTAL = "total_count"
# CSV Fields
INVESTIGATION_CASE_RENDERER_FIELDS = [
"case_subject__name",
"case_subject__address",
"case_subject__age",
"case_subject__is_male",
"case_subject__district",
"case_subject__sub_district",
"case_relation",
"reference_case__case_subject__name",
"outcome",
"medical_symptoms",
"risk_factors",
"medical_facility_reference",
"created_at",
"author__name",
]
INVESTIGATION_CASE_HEADER_FIELDS = [
"nama",
"alamat",
"usia",
"jenis_kelamin",
"kabupaten",
"kecamatan",
"jenis_kontak",
"subyek_kasus_acuan",
"hasil_pemeriksaan",
"gejala_medis",
"faktor_risiko",
"rujukan_fasilitas_kesehatan",
"tanggal_pencatatan",
"kader_pencatat",
]
from rest_framework_csv.renderers import CSVRenderer
INVESTIGATION_CASE_RENDERER_FIELDS = [
"id",
"case_subject__age",
"case_subject__is_male",
"case_subject__district",
"outcome",
"is_positive",
"case_relation",
"medical_symptoms",
"risk_factors",
"is_referral_needed",
"medical_facility_reference",
"created_at",
"author__name",
]
from apps.exportables.constants import INVESTIGATION_CASE_HEADER_FIELDS
class InvestigationCaseCSVRenderer(CSVRenderer):
header = INVESTIGATION_CASE_RENDERER_FIELDS
header = INVESTIGATION_CASE_HEADER_FIELDS
......@@ -2,13 +2,22 @@ import json
import csv
import io
from rest_framework import status
from rest_framework.test import APITestCase
from rest_framework.authtoken.models import Token
from rest_framework.test import APITestCase, APIClient
from apps.constants import HEADER_PREFIX
from apps.accounts.tests.factories.accounts import AccountFactory, UserFactory
from apps.cases.models import CaseSubject
from apps.cases.tests.factories.case_subjects import CaseSubjectFactory
from apps.cases.tests.factories.cases import InvestigationCaseFactory
from apps.exportables.renderers import INVESTIGATION_CASE_RENDERER_FIELDS
from apps.exportables.constants import (
INVESTIGATION_CASE_HEADER_FIELDS,
INVESTIGATION_CASE_RENDERER_FIELDS,
)
def init_data():
......@@ -57,8 +66,15 @@ def init_data():
class ExportableViewTest(APITestCase):
@classmethod
def setUpTestData(cls):
cls.user = UserFactory(username="user", password="justpass")
cls.admin = AccountFactory(admin=True, user=cls.user)
cls.token, _ = Token.objects.get_or_create(user=cls.user)
init_data()
def setUp(self):
self.client = APIClient(HTTP_AUTHORIZATION=HEADER_PREFIX + self.token.key)
def test_exportable_data_return_values(self):
url = "/exportables/"
response = self.client.get(url)
......@@ -189,9 +205,16 @@ class ExportableViewTest(APITestCase):
class ExportInvestigationCaseViewTest(APITestCase):
@classmethod
def setUpTestData(cls):
cls.user = UserFactory(username="user", password="justpass")
cls.admin = AccountFactory(admin=True, user=cls.user)
cls.token, _ = Token.objects.get_or_create(user=cls.user)
cls.BASE_URL = "/exportables/investigation-cases-csv/"
init_data()
def setUp(self):
self.client = APIClient(HTTP_AUTHORIZATION=HEADER_PREFIX + self.token.key)
def export_csv_test_util(self, filter):
url = self.BASE_URL + filter
response = self.client.get(url)
......@@ -207,7 +230,7 @@ class ExportInvestigationCaseViewTest(APITestCase):
body = list(reader)
headers = body.pop(0)
self.assertEqual(headers, INVESTIGATION_CASE_RENDERER_FIELDS)
self.assertEqual(headers, INVESTIGATION_CASE_HEADER_FIELDS)
return body
def wrong_query_param_test_util(self, filter):
......
import json
import time
from django.utils import timezone
from apps.exportables.constants import (
DISTRICT,
DISTRICTS,
......@@ -6,10 +10,15 @@ from apps.exportables.constants import (
NEGATIVE,
POSITIVE,
TOTAL,
UNDETERMINED
UNDETERMINED,
INVESTIGATION_CASE_HEADER_FIELDS,
INVESTIGATION_CASE_RENDERER_FIELDS,
)
# CASE STATISTIC COUNTS
def generate_initial_counts():
return {
POSITIVE: 0,
......@@ -43,3 +52,40 @@ def map_sex_value(sex):
if sex:
return MALE
return FEMALE
# CSV EXPORTS
def format_custom_csv_rows(cases_csv_rows):
formatted_rows = []
FIELDS_LENGTH = len(INVESTIGATION_CASE_RENDERER_FIELDS)
for row in cases_csv_rows:
formatted_row = {}
for field_name_index in range(FIELDS_LENGTH):
original_field_name = INVESTIGATION_CASE_RENDERER_FIELDS[field_name_index]
target_field_name = INVESTIGATION_CASE_HEADER_FIELDS[field_name_index]
formatted_row[target_field_name] = row[original_field_name]
value = formatted_row["jenis_kelamin"]
formatted_row["jenis_kelamin"] = "Laki-laki" if value else "Perempuan"
value = json.loads(formatted_row["gejala_medis"])
selected_values = [key for key in value.keys() if value[key]]
formatted_row["gejala_medis"] = "; ".join(selected_values)
value = json.loads(formatted_row["faktor_risiko"])
selected_values = [key for key in value.keys() if value[key]]
formatted_row["faktor_risiko"] = "; ".join(selected_values)
value = formatted_row["tanggal_pencatatan"]
formatted_row["tanggal_pencatatan"] = timezone.localtime(value)
formatted_rows.append(formatted_row)
return formatted_rows
......@@ -9,6 +9,7 @@ from apps.cases.models import (
CaseSubject,
InvestigationCase,
)
from apps.commons.permissions import IsAuthenticated
from apps.exportables.constants import (
AGE,
DISTRICT,
......@@ -19,26 +20,27 @@ from apps.exportables.constants import (
POSITIVE,
SEX,
TOTAL,
UNDETERMINED
UNDETERMINED,
INVESTIGATION_CASE_RENDERER_FIELDS,
)
from apps.exportables.utils import (
format_custom_csv_rows,
generate_initial_counts,
generate_initial_group_counts,
map_outcome_value,
map_sex_value,
)
from apps.exportables.renderers import (
InvestigationCaseCSVRenderer,
INVESTIGATION_CASE_RENDERER_FIELDS,
)
from apps.exportables.renderers import InvestigationCaseCSVRenderer
class CaseCountsView(APIView):
permission_classes = (IsAuthenticated,)
def get(self, request, format=None):
case_subjects = CaseSubject.objects.all()
investigation_cases = (InvestigationCase.objects
investigation_cases = (
InvestigationCase.objects
.values("case_subject")
.annotate(latest_investigation_case=Max("created_at"))
.order_by()
......@@ -91,6 +93,7 @@ class CaseCountsView(APIView):
class ExportInvestigationCaseView(APIView):
permission_classes = (IsAuthenticated,)
renderer_classes = (InvestigationCaseCSVRenderer,)
def get(self, request, format=None):
......@@ -127,9 +130,14 @@ class ExportInvestigationCaseView(APIView):
cases.prefetch_related(
"case_subject",
"reference_case",
"author").values(
*INVESTIGATION_CASE_RENDERER_FIELDS))
"author"
).values(
*INVESTIGATION_CASE_RENDERER_FIELDS
)
)
formatted_data = format_custom_csv_rows(data)
filename = "cases-{}.csv".format(timezone.localtime(timezone.now()))
headers = {"Content-Disposition": 'attachment; filename="{}"'.format(filename)}
return Response(data, headers=headers)
return Response(formatted_data, headers=headers)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment