Skip to content

Commit

Permalink
Merge pull request #433 from bento-platform/feat/individual-phenopackets
Browse files Browse the repository at this point in the history
feat(patients): add individual phenopackets endpoint w/ attachment option
  • Loading branch information
davidlougheed committed Sep 12, 2023
2 parents 1b0dfed + 0c2e60e commit 0c9fc57
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 4 deletions.
27 changes: 26 additions & 1 deletion chord_metadata_service/patients/api_views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import re

from datetime import datetime

from rest_framework import viewsets, filters, mixins, serializers
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.settings import api_settings
from rest_framework.views import APIView
from django.conf import settings
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
Expand All @@ -22,6 +25,7 @@
from chord_metadata_service.logger import logger
from chord_metadata_service.phenopackets.api_views import BIOSAMPLE_PREFETCH, PHENOPACKET_PREFETCH
from chord_metadata_service.phenopackets.models import Phenopacket
from chord_metadata_service.phenopackets.serializers import PhenopacketSerializer
from chord_metadata_service.restapi.api_renderers import (
FHIRRenderer,
PhenopacketsRenderer,
Expand Down Expand Up @@ -97,6 +101,27 @@ def list(self, request, *args, **kwargs):

return super(IndividualViewSet, self).list(request, *args, **kwargs)

@action(detail=True, methods=["GET", "POST"])
def phenopackets(self, request, *_args, **_kwargs):
as_attachment = request.query_params.get("attachment", "") in ("1", "true", "yes")
individual = self.get_object()

phenopackets = (
Phenopacket.objects
.filter(subject=individual)
.prefetch_related(*PHENOPACKET_PREFETCH)
.order_by("id")
)

filename_safe_id = re.sub(r"[\\/:*?\"<>|]", "_", individual.id)
return Response(
PhenopacketSerializer(phenopackets, many=True).data,
headers=(
{"Content-Disposition": f"attachment; filename=\"{filename_safe_id}_phenopackets.json\""}
if as_attachment else {}
),
)


class BatchViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
Expand Down
18 changes: 15 additions & 3 deletions chord_metadata_service/patients/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def test_csv_export(self):
self.assertIn(column, [column_name.lower() for column_name in headers])


class IndividualFullTextSearchTest(APITestCase):
class IndividualWithPhenopacketSearchTest(APITestCase):
""" Test for api/individuals?search= """

def setUp(self):
Expand All @@ -165,7 +165,7 @@ def setUp(self):
**ph_c.valid_phenopacket(subject=self.individual_one, meta_data=self.metadata_1)
)

def test_search(self):
def test_search(self): # test full-text search
get_resp_1 = self.client.get('/api/individuals?search=P49Y')
self.assertEqual(get_resp_1.status_code, status.HTTP_200_OK)
response_obj_1 = get_resp_1.json()
Expand All @@ -176,13 +176,25 @@ def test_search(self):
response_obj_2 = get_resp_2.json()
self.assertEqual(len(response_obj_2['results']), 2)

def test_search_bento_search_format(self):
def test_search_bento_search_format(self): # test full-text search - bento search result format
get_resp_1 = self.client.get('/api/individuals?search=P49Y&format=bento_search_result')
self.assertEqual(get_resp_1.status_code, status.HTTP_200_OK)
response_obj_1 = get_resp_1.json()
self.assertEqual(len(response_obj_1['results']), 1)
self.assertEqual(len(response_obj_1['results'][0]), 4) # 4 fields in the bento search response

def test_individual_phenopackets(self):
get_resp = self.client.get(f"/api/individuals/{self.individual_one.id}/phenopackets")
self.assertEqual(get_resp.status_code, status.HTTP_200_OK)
response_obj_1 = get_resp.json()
self.assertEqual(len(response_obj_1), 1) # 1 phenopacket for individual

post_resp = self.client.post(f"/api/individuals/{self.individual_one.id}/phenopackets?attachment=1")
self.assertEqual(post_resp.status_code, status.HTTP_200_OK)
self.assertIn("attachment; filename=", post_resp.headers.get("Content-Disposition", ""))
response_obj_2 = post_resp.json()
self.assertEqual(len(response_obj_2), 1) # 1 phenopacket for individual, still


# Note: the next five tests use the same setUp method. Initially they were
# all combined in the same class. But this caused bugs with regard to unavailable
Expand Down

0 comments on commit 0c9fc57

Please sign in to comment.