From 9ddc97a04b81358466ef6c85088eb45d07521065 Mon Sep 17 00:00:00 2001 From: william Date: Wed, 4 Dec 2024 23:09:01 +1100 Subject: [PATCH 1/5] add is_leaf_node --- .../metadata-manager/app/viewsets/sample.py | 23 ++++++++++++++----- .../metadata-manager/app/viewsets/subject.py | 10 ++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py index 562bd187c..7e86877ef 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py @@ -1,4 +1,4 @@ -from drf_spectacular.utils import extend_schema +from drf_spectacular.utils import extend_schema, OpenApiParameter from rest_framework.decorators import action from app.models import Sample @@ -13,16 +13,27 @@ class SampleViewSet(BaseViewSet): queryset = Sample.objects.all() orcabus_id_prefix = Sample.orcabus_id_prefix + def get_queryset(self): + qs = self.queryset + query_params = self.get_query_params() + + is_empty_lib = query_params.getlist("is_empty_library", None) + if is_empty_lib: + query_params.pop("is_empty_library") + qs = qs.filter(library=None) + + return Sample.objects.get_by_keyword(qs, **query_params) + @extend_schema(parameters=[ - SampleSerializer + SampleSerializer, + OpenApiParameter(name='is_empty_library', + description="Filter where it is not linked to a library.", + required=False, + type=bool), ]) def list(self, request, *args, **kwargs): return super().list(request, *args, **kwargs) - def get_queryset(self): - query_params = self.get_query_params() - return Sample.objects.get_by_keyword(**query_params) - @extend_schema(responses=SampleHistorySerializer(many=True), description="Retrieve the history of this model") @action(detail=True, methods=['get'], url_name='history', url_path='history') def retrieve_history(self, request, *args, **kwargs): diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py index e12c6f8c8..51d069ee0 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py @@ -1,5 +1,6 @@ from drf_spectacular.utils import extend_schema, OpenApiParameter from rest_framework.decorators import action +from rest_framework.viewsets import ModelViewSet from app.models import Subject, Library from app.serializers.subject import SubjectSerializer, SubjectDetailSerializer, SubjectHistorySerializer @@ -32,6 +33,11 @@ def get_queryset(self): qs = qs.filter(library__orcabus_id=library_orcabus_id) + is_empty_lib = query_params.getlist("is_empty_library", None) + if is_empty_lib: + query_params.pop("is_empty_library") + qs = qs.filter(library=None) + return Subject.objects.get_by_keyword(qs, **query_params) @extend_schema(parameters=[ @@ -44,6 +50,10 @@ def get_queryset(self): description="Filter based on 'orcabus_id' of the library associated with the subject.", required=False, type=str), + OpenApiParameter(name='is_empty_library', + description="Filter where it is not linked to a library.", + required=False, + type=bool), ]) def list(self, request, *args, **kwargs): return super().list(request, *args, **kwargs) From d4527e22fba70ee63ff9b45b61a2b66cbd77f3d2 Mon Sep 17 00:00:00 2001 From: william Date: Fri, 6 Dec 2024 13:00:33 +1100 Subject: [PATCH 2/5] Update base.py --- .../stacks/metadata-manager/app/viewsets/base.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py index ce54bc5dc..5e7d4468c 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py @@ -1,21 +1,24 @@ from abc import ABC +from rest_framework.mixins import DestroyModelMixin + from app.pagination import StandardResultsSetPagination from django.shortcuts import get_object_or_404 -from rest_framework import filters +from rest_framework import filters, status from rest_framework.response import Response -from rest_framework.viewsets import ReadOnlyModelViewSet +from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet -class BaseViewSet(ReadOnlyModelViewSet, ABC): +class BaseViewSet(ModelViewSet, ABC): lookup_value_regex = "[^/]+" # This is to allow for special characters in the URL orcabus_id_prefix = '' ordering_fields = "__all__" ordering = ["-orcabus_id"] pagination_class = StandardResultsSetPagination filter_backends = [filters.OrderingFilter, filters.SearchFilter] + http_method_names = ['get', 'post', 'patch', 'delete'] def retrieve(self, request, *args, **kwargs): """ From 84a05133fda168bc13d8b1666dd88649d301dbda Mon Sep 17 00:00:00 2001 From: william Date: Fri, 6 Dec 2024 15:08:00 +1100 Subject: [PATCH 3/5] user audit for CRUD endpoint --- .../metadata-manager/app/viewsets/base.py | 38 ++++++++++++++ .../metadata-manager/app/viewsets/contact.py | 28 ++++++++--- .../app/viewsets/individual.py | 21 +++++--- .../metadata-manager/app/viewsets/library.py | 48 +++++++++++------- .../metadata-manager/app/viewsets/project.py | 21 ++++++-- .../metadata-manager/app/viewsets/sample.py | 28 ++++++++--- .../metadata-manager/app/viewsets/subject.py | 49 ++++++++++++------- 7 files changed, 171 insertions(+), 62 deletions(-) diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py index 5e7d4468c..b706598ca 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py @@ -1,5 +1,6 @@ from abc import ABC +from drf_spectacular.utils import extend_schema from rest_framework.mixins import DestroyModelMixin from app.pagination import StandardResultsSetPagination @@ -10,6 +11,8 @@ from rest_framework.response import Response from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet +from app.viewsets.utils import get_email_from_jwt + class BaseViewSet(ModelViewSet, ABC): lookup_value_regex = "[^/]+" # This is to allow for special characters in the URL @@ -78,3 +81,38 @@ def retrieve_history(self, request, *args, **kwargs): serializer = history_serializer(page, many=True) return self.get_paginated_response(serializer.data) + + + def perform_destroy(self, instance): + """ + The perform_destroy method is overridden to allow for the _history_user to be set. + """ + requester_email = get_email_from_jwt(self.request) + if not requester_email: + raise ValueError("The requester email is not found in the JWT token.") + + instance._history_user = requester_email + super().perform_destroy(instance) + + + def perform_update(self, serializer): + """ + The perform_destroy method is overridden to allow for the _history_user to be set. + """ + requester_email = get_email_from_jwt(self.request) + if not requester_email: + raise ValueError("The requester email is not found in the JWT token.") + + serializer._history_user = requester_email + super().perform_update(serializer) + + def perform_create(self, serializer): + """ + The perform_create method is overridden to allow for the _history_user to be set. + """ + requester_email = get_email_from_jwt(self.request) + if not requester_email: + raise ValueError("The requester email is not found in the JWT token.") + + serializer._history_user = requester_email + super().perform_create(serializer) diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/contact.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/contact.py index 52f59498a..36189c5b9 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/contact.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/contact.py @@ -8,20 +8,32 @@ class ContactViewSet(BaseViewSet): - serializer_class = ContactDetailSerializer + serializer_class = ContactSerializer search_fields = Contact.get_base_fields() - queryset = Contact.objects.prefetch_related('project_set').all() + queryset = Contact.objects.all() orcabus_id_prefix = Contact.orcabus_id_prefix - @extend_schema(parameters=[ - ContactSerializer - ]) + def get_queryset(self): + query_params = super().get_query_params() + return Contact.objects.get_by_keyword(**query_params) + + @extend_schema(responses=ContactDetailSerializer(many=False)) + def retrieve(self, request, *args, **kwargs): + self.serializer_class = ContactDetailSerializer + self.queryset = Contact.objects.prefetch_related('project_set').all() + return super().retrieve(request, *args, **kwargs) + + @extend_schema( + parameters=[ + ContactSerializer + ], + responses=ContactDetailSerializer(many=True), + ) def list(self, request, *args, **kwargs): + self.serializer_class = ContactDetailSerializer + self.queryset = Contact.objects.prefetch_related('project_set').all() return super().list(request, *args, **kwargs) - def get_queryset(self): - query_params = self.get_query_params() - return Contact.objects.get_by_keyword(**query_params) @extend_schema(responses=ContactHistorySerializer(many=True), description="Retrieve the history of this model") @action(detail=True, methods=['get'], url_name='history', url_path='history') diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/individual.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/individual.py index a0ae40b2e..aed759204 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/individual.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/individual.py @@ -2,21 +2,30 @@ from rest_framework.decorators import action from app.models import Individual -from app.serializers.individual import IndividualDetailSerializer, IndividualHistorySerializer +from app.serializers.individual import IndividualDetailSerializer, IndividualHistorySerializer, IndividualSerializer from .base import BaseViewSet class IndividualViewSet(BaseViewSet): - serializer_class = IndividualDetailSerializer + serializer_class = IndividualSerializer search_fields = Individual.get_base_fields() - queryset = Individual.objects.prefetch_related('subject_set').all() + queryset = Individual.objects.all() orcabus_id_prefix = Individual.orcabus_id_prefix - @extend_schema(parameters=[ - IndividualDetailSerializer - ]) + @extend_schema(responses=IndividualDetailSerializer(many=False)) + def retrieve(self, request, *args, **kwargs): + self.serializer_class = IndividualDetailSerializer + self.queryset = Individual.objects.prefetch_related('subject_set').all() + return super().retrieve(request, *args, **kwargs) + + @extend_schema( + parameters=[IndividualDetailSerializer], + responses=IndividualDetailSerializer(many=True), + ) def list(self, request, *args, **kwargs): + self.serializer_class = IndividualDetailSerializer + self.queryset = Individual.objects.prefetch_related('subject_set').all() return super().list(request, *args, **kwargs) def get_queryset(self): diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/library.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/library.py index c315154fb..a5f5f665b 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/library.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/library.py @@ -8,9 +8,10 @@ class LibraryViewSet(BaseViewSet): - serializer_class = LibraryDetailSerializer + serializer_class = LibrarySerializer + detail_serializer_class = LibraryDetailSerializer search_fields = Library.get_base_fields() - queryset = Library.objects.select_related('sample').select_related('subject').prefetch_related('project_set').all() + queryset = Library.objects.all() orcabus_id_prefix = Library.orcabus_id_prefix def get_queryset(self): @@ -35,22 +36,35 @@ def get_queryset(self): # Continue filtering by the keys inside the library model return Library.objects.get_by_keyword(qs, **query_params) - @extend_schema(parameters=[ - LibrarySerializer, - OpenApiParameter(name='coverage[lte]', - description="Filter based on 'coverage' that is less than or equal to the given value.", - required=False, - type=float), - OpenApiParameter(name='coverage[gte]', - description="Filter based on 'coverage' that is greater than or equal to the given value.", - required=False, - type=float), - OpenApiParameter(name='project_id', - description="Filter where the associated the project has the given 'project_id'.", - required=False, - type=float), - ]) + @extend_schema(responses=LibraryDetailSerializer(many=False)) + def retrieve(self, request, *args, **kwargs): + self.serializer_class = LibraryDetailSerializer + self.queryset = Library.objects.select_related('sample').select_related('subject').prefetch_related( + 'project_set').all() + return super().retrieve(request, *args, **kwargs) + + @extend_schema( + parameters=[ + LibrarySerializer, + OpenApiParameter(name='coverage[lte]', + description="Filter based on 'coverage' that is less than or equal to the given value.", + required=False, + type=float), + OpenApiParameter(name='coverage[gte]', + description="Filter based on 'coverage' that is greater than or equal to the given value.", + required=False, + type=float), + OpenApiParameter(name='project_id', + description="Filter where the associated the project has the given 'project_id'.", + required=False, + type=float), + ], + responses=LibraryDetailSerializer(many=True), + ) def list(self, request, *args, **kwargs): + self.serializer_class = LibraryDetailSerializer + self.queryset = Library.objects.select_related('sample').select_related('subject').prefetch_related( + 'project_set').all() return super().list(request, *args, **kwargs) @extend_schema(responses=LibraryHistorySerializer(many=True), description="Retrieve the history of this model") diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/project.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/project.py index 8d4013f58..d86ed1119 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/project.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/project.py @@ -8,15 +8,26 @@ class ProjectViewSet(BaseViewSet): - serializer_class = ProjectDetailSerializer + serializer_class = ProjectSerializer search_fields = Project.get_base_fields() - queryset = Project.objects.prefetch_related("contact_set").all() + queryset = Project.objects.all() orcabus_id_prefix = Project.orcabus_id_prefix - @extend_schema(parameters=[ - ProjectSerializer - ]) + @extend_schema(responses=ProjectDetailSerializer(many=False)) + def retrieve(self, request, *args, **kwargs): + self.serializer_class = ProjectDetailSerializer + self.queryset = Project.objects.prefetch_related("contact_set").all() + return super().retrieve(request, *args, **kwargs) + + @extend_schema( + parameters=[ + ProjectSerializer + ], + responses=ProjectDetailSerializer(many=True), + ) def list(self, request, *args, **kwargs): + self.serializer_class = ProjectDetailSerializer + self.queryset = Project.objects.prefetch_related("contact_set").all() return super().list(request, *args, **kwargs) def get_queryset(self): diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py index 7e86877ef..2740fd777 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py @@ -8,7 +8,7 @@ class SampleViewSet(BaseViewSet): - serializer_class = SampleDetailSerializer + serializer_class = SampleSerializer search_fields = Sample.get_base_fields() queryset = Sample.objects.all() orcabus_id_prefix = Sample.orcabus_id_prefix @@ -24,14 +24,26 @@ def get_queryset(self): return Sample.objects.get_by_keyword(qs, **query_params) - @extend_schema(parameters=[ - SampleSerializer, - OpenApiParameter(name='is_empty_library', - description="Filter where it is not linked to a library.", - required=False, - type=bool), - ]) + @extend_schema(responses=SampleDetailSerializer(many=False)) + def retrieve(self, request, *args, **kwargs): + self.serializer_class = SampleDetailSerializer + self.queryset = Sample.objects.prefetch_related('library_set').all() + return super().retrieve(request, *args, **kwargs) + + + @extend_schema( + parameters=[ + SampleSerializer, + OpenApiParameter(name='is_empty_library', + description="Filter where it is not linked to a library.", + required=False, + type=bool), + ], + responses=SampleDetailSerializer(many=True), + ) def list(self, request, *args, **kwargs): + self.queryset = Sample.objects.prefetch_related('library_set').all() + self.serializer_class = SampleDetailSerializer return super().list(request, *args, **kwargs) @extend_schema(responses=SampleHistorySerializer(many=True), description="Retrieve the history of this model") diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py index 51d069ee0..87c5be971 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py @@ -1,6 +1,5 @@ from drf_spectacular.utils import extend_schema, OpenApiParameter from rest_framework.decorators import action -from rest_framework.viewsets import ModelViewSet from app.models import Subject, Library from app.serializers.subject import SubjectSerializer, SubjectDetailSerializer, SubjectHistorySerializer @@ -8,9 +7,9 @@ class SubjectViewSet(BaseViewSet): - serializer_class = SubjectDetailSerializer + serializer_class = SubjectSerializer search_fields = Subject.get_base_fields() - queryset = Subject.objects.prefetch_related('individual_set').prefetch_related('library_set').all() + queryset = Subject.objects.all() orcabus_id_prefix = Subject.orcabus_id_prefix def get_queryset(self): @@ -40,22 +39,36 @@ def get_queryset(self): return Subject.objects.get_by_keyword(qs, **query_params) - @extend_schema(parameters=[ - SubjectSerializer, - OpenApiParameter(name='library_id', - description="Filter based on 'library_id' of the library associated with the subject.", - required=False, - type=str), - OpenApiParameter(name='library_orcabus_id', - description="Filter based on 'orcabus_id' of the library associated with the subject.", - required=False, - type=str), - OpenApiParameter(name='is_empty_library', - description="Filter where it is not linked to a library.", - required=False, - type=bool), - ]) + + @extend_schema(responses=SubjectDetailSerializer(many=False)) + def retrieve(self, request, *args, **kwargs): + self.serializer_class = SubjectDetailSerializer + self.queryset = Subject.objects.prefetch_related('individual_set').prefetch_related('library_set').all() + return super().retrieve(request, *args, **kwargs) + + + + @extend_schema( + parameters=[ + SubjectSerializer, + OpenApiParameter(name='library_id', + description="Filter based on 'library_id' of the library associated with the subject.", + required=False, + type=str), + OpenApiParameter(name='library_orcabus_id', + description="Filter based on 'orcabus_id' of the library associated with the subject.", + required=False, + type=str), + OpenApiParameter(name='is_empty_library', + description="Filter where it is not linked to a library.", + required=False, + type=bool), + ], + responses=SubjectDetailSerializer(many=True), + ) def list(self, request, *args, **kwargs): + self.serializer_class = SubjectDetailSerializer + self.queryset = Subject.objects.prefetch_related('individual_set').prefetch_related('library_set').all() return super().list(request, *args, **kwargs) @extend_schema(responses=SubjectHistorySerializer(many=True), description="Retrieve the history of this model") From 24656fdc8dd4d509c9bdc8a893b5d04e930bfb1a Mon Sep 17 00:00:00 2001 From: william Date: Mon, 9 Dec 2024 17:55:36 +1100 Subject: [PATCH 4/5] add api-gw route --- lib/workload/components/api-gateway/index.ts | 1 + .../app/tests/test_viewsets.py | 36 ++++++++++++++++++- .../metadata-manager/app/tests/utils.py | 10 ++++++ .../metadata-manager/app/viewsets/base.py | 2 +- .../deploy/construct/lambda-api/index.ts | 18 ++++++++++ 5 files changed, 65 insertions(+), 2 deletions(-) diff --git a/lib/workload/components/api-gateway/index.ts b/lib/workload/components/api-gateway/index.ts index 7bad949d0..27c314a51 100644 --- a/lib/workload/components/api-gateway/index.ts +++ b/lib/workload/components/api-gateway/index.ts @@ -99,6 +99,7 @@ export class ApiGatewayConstruct extends Construct { CorsHttpMethod.OPTIONS, CorsHttpMethod.POST, CorsHttpMethod.PATCH, + CorsHttpMethod.DELETE, ], allowOrigins: props.corsAllowOrigins, maxAge: Duration.days(10), diff --git a/lib/workload/stateless/stacks/metadata-manager/app/tests/test_viewsets.py b/lib/workload/stateless/stacks/metadata-manager/app/tests/test_viewsets.py index 15a7a457c..ea44bd67b 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/tests/test_viewsets.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/tests/test_viewsets.py @@ -1,13 +1,18 @@ +import json import logging from django.test import TestCase +from app.models import Library, Sample from app.tests.factories import LIBRARY_1, SUBJECT_1, SAMPLE_1 -from app.tests.utils import insert_mock_1 +from app.tests.utils import insert_mock_1, is_obj_exists logger = logging.getLogger() logger.setLevel(logging.INFO) +# pragma: allowlist nextline secret +TEST_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJlbWFpbCI6ImpvaG4uZG9lQGV4YW1wbGUuY29tIn0.1XOO35Ozn1XNEj_W7RFefNfJnVm7C1pm7MCEBPbCkJ4" + def version_endpoint(ep: str): return "api/v1/" + ep @@ -68,3 +73,32 @@ def test_get_api(self): "No results are expected for unrecognized query parameter", ) + def test_delete_api(self): + """ + python manage.py test app.tests.test_viewsets.LabViewSetTestCase.test_delete_api + """ + + library = Library.objects.get(library_id=LIBRARY_1['library_id']) + self.client.delete(f"/{version_endpoint(f"library/{library.orcabus_id}/")}", + headers={'Authorization': f'Bearer {TEST_JWT}'}) + self.assertFalse(is_obj_exists(Library, library_id=LIBRARY_1['library_id']), "Library should be deleted") + + sample = Sample.objects.get(sample_id=SAMPLE_1['sample_id']) + self.client.delete(f"/{version_endpoint(f"sample/{sample.orcabus_id}/")}", + headers={'Authorization': f'Bearer {TEST_JWT}'}) + self.assertFalse(is_obj_exists(Sample, sample_id=SAMPLE_1['sample_id']), "Sample should be deleted") + + def test_patch_api(self): + """ + python manage.py test app.tests.test_viewsets.LabViewSetTestCase.test_patch_api + """ + new_coverage = 10.0 + + library = Library.objects.get(library_id=LIBRARY_1['library_id']) + + self.assertEqual(library.coverage, LIBRARY_1['coverage'], "Coverage should be the same") + self.client.patch(f"/{version_endpoint(f"library/{library.orcabus_id}/")}", + data=json.dumps({"coverage":new_coverage}), + headers={'Authorization': f'Bearer {TEST_JWT}', 'Content-Type': 'application/json'}) + library = Library.objects.get(library_id=LIBRARY_1['library_id']) + self.assertEqual(library.coverage, new_coverage, "Coverage should be updated") diff --git a/lib/workload/stateless/stacks/metadata-manager/app/tests/utils.py b/lib/workload/stateless/stacks/metadata-manager/app/tests/utils.py index c7c855099..b7edcd290 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/tests/utils.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/tests/utils.py @@ -1,3 +1,5 @@ +from django.core.exceptions import ObjectDoesNotExist + from app.models import Subject, Sample, Library, Project, Contact, Individual from app.tests.factories import LibraryFactory, IndividualFactory, SubjectFactory, SampleFactory, \ ProjectFactory, ContactFactory @@ -35,3 +37,11 @@ def insert_mock_1(): subject.individual_set.add(individual) subject.save() + + +def is_obj_exists(obj, **kwargs): + try: + obj.objects.get(**kwargs) + return True + except ObjectDoesNotExist: + return False diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py index b706598ca..a5443faa7 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/base.py @@ -21,7 +21,7 @@ class BaseViewSet(ModelViewSet, ABC): ordering = ["-orcabus_id"] pagination_class = StandardResultsSetPagination filter_backends = [filters.OrderingFilter, filters.SearchFilter] - http_method_names = ['get', 'post', 'patch', 'delete'] + http_method_names = ['get', 'patch', 'delete'] def retrieve(self, request, *args, **kwargs): """ diff --git a/lib/workload/stateless/stacks/metadata-manager/deploy/construct/lambda-api/index.ts b/lib/workload/stateless/stacks/metadata-manager/deploy/construct/lambda-api/index.ts index ddcdcb6dc..688284db0 100644 --- a/lib/workload/stateless/stacks/metadata-manager/deploy/construct/lambda-api/index.ts +++ b/lib/workload/stateless/stacks/metadata-manager/deploy/construct/lambda-api/index.ts @@ -65,6 +65,24 @@ export class LambdaAPIConstruct extends Construct { integration: apiIntegration, routeKey: HttpRouteKey.with(`/api/${this.API_VERSION}/{PROXY+}`, HttpMethod.GET), }); + new HttpRoute(this, 'PostHttpRoute', { + httpApi: apiGW.httpApi, + integration: apiIntegration, + authorizer: apiGW.authStackHttpLambdaAuthorizer, + routeKey: HttpRouteKey.with(`/api/${this.API_VERSION}/{PROXY+}`, HttpMethod.POST), + }); + new HttpRoute(this, 'PatchHttpRoute', { + httpApi: apiGW.httpApi, + integration: apiIntegration, + authorizer: apiGW.authStackHttpLambdaAuthorizer, + routeKey: HttpRouteKey.with(`/api/${this.API_VERSION}/{PROXY+}`, HttpMethod.PATCH), + }); + new HttpRoute(this, 'DeleteHttpRoute', { + httpApi: apiGW.httpApi, + integration: apiIntegration, + authorizer: apiGW.authStackHttpLambdaAuthorizer, + routeKey: HttpRouteKey.with(`/api/${this.API_VERSION}/{PROXY+}`, HttpMethod.DELETE), + }); // Add permission, HTTP route, and env-var for the sync lambdas From 2385f0aef93708ed55b9442f945405679f47705c Mon Sep 17 00:00:00 2001 From: william Date: Mon, 9 Dec 2024 18:12:28 +1100 Subject: [PATCH 5/5] rename variable --- .../stacks/metadata-manager/app/viewsets/sample.py | 8 ++++---- .../stacks/metadata-manager/app/viewsets/subject.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py index 2740fd777..351fc8aa4 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/sample.py @@ -17,9 +17,9 @@ def get_queryset(self): qs = self.queryset query_params = self.get_query_params() - is_empty_lib = query_params.getlist("is_empty_library", None) - if is_empty_lib: - query_params.pop("is_empty_library") + is_library_none = query_params.getlist("is_library_none", None) + if is_library_none: + query_params.pop("is_library_none") qs = qs.filter(library=None) return Sample.objects.get_by_keyword(qs, **query_params) @@ -34,7 +34,7 @@ def retrieve(self, request, *args, **kwargs): @extend_schema( parameters=[ SampleSerializer, - OpenApiParameter(name='is_empty_library', + OpenApiParameter(name='is_library_none', description="Filter where it is not linked to a library.", required=False, type=bool), diff --git a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py index 87c5be971..df88a583e 100644 --- a/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py +++ b/lib/workload/stateless/stacks/metadata-manager/app/viewsets/subject.py @@ -32,9 +32,9 @@ def get_queryset(self): qs = qs.filter(library__orcabus_id=library_orcabus_id) - is_empty_lib = query_params.getlist("is_empty_library", None) - if is_empty_lib: - query_params.pop("is_empty_library") + is_library_none = query_params.getlist("is_library_none", None) + if is_library_none: + query_params.pop("is_library_none") qs = qs.filter(library=None) return Subject.objects.get_by_keyword(qs, **query_params) @@ -59,7 +59,7 @@ def retrieve(self, request, *args, **kwargs): description="Filter based on 'orcabus_id' of the library associated with the subject.", required=False, type=str), - OpenApiParameter(name='is_empty_library', + OpenApiParameter(name='is_library_none', description="Filter where it is not linked to a library.", required=False, type=bool),