diff --git a/CHANGELOG.md b/CHANGELOG.md index 0967dd20..f2a81f6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Created graphics for the services that were re-analyzed [#290](https://github.com/BU-ISCIII/iskylims/pull/290) - Enhance both `install.sh` and `docker_install.sh`, fix data loading issues [#327](https://github.com/BU-ISCIII/iskylims/pull/327) - Included thorough description for wetlab API's update_lab() method [#361](https://github.com/BU-ISCIII/iskylims/pull/361) +- Included new API function lab-request-mapping to get LabRequest fields ontology map [#377](https://github.com/BU-ISCIII/iskylims/pull/377) +- Improved responses in API create-sample-data by adding ERROR messages and data [#377](https://github.com/BU-ISCIII/iskylims/pull/377) #### Fixes @@ -56,8 +58,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Fixed wetlab API's labrequest.serializer update method to work properly [#361](https://github.com/BU-ISCIII/iskylims/pull/361) - Adapted update_lab serializer call to new serializer update method [#361](https://github.com/BU-ISCIII/iskylims/pull/361) - Leave missing submitting_fields as empty string instead of crashing in wetlab.api.create_sample_data [#363](https://github.com/BU-ISCIII/iskylims/pull/363) - - +- Fixed wetlab API create-sample-data error when submitting_institution fields were not provided [#377](https://github.com/BU-ISCIII/iskylims/pull/377) #### Changed @@ -69,6 +70,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Renamed method `get_delivery_date` to `get_delivered_date` for clarity. - Improved query performance and excluded rejected/archived services from ongoing list. (#299) - Updated sample metadata fields with standardized ontology mappings and schema alignment.[#358](https://github.com/BU-ISCIII/iskylims/pull/358) +- API create-sample-data Lab data mapping moved to core_config.LAB_REQUEST_ONTOLOGY_MAP [#377](https://github.com/BU-ISCIII/iskylims/pull/377) #### Removed diff --git a/core/core_config.py b/core/core_config.py index b0b605f7..486013d7 100644 --- a/core/core_config.py +++ b/core/core_config.py @@ -334,3 +334,23 @@ ] ERROR_PROJECT_FIELD_NOOPTION = ["Project field", "only has the following options:"] ERROR_PROJECT_FIELD_EMPTY = ["Project field", "is empty"] + +LAB_REQUEST_ONTOLOGY_MAP = { + "GENEPIO:0001153": ("lab_name", "collecting_institution"), + "SNOMED:423901009": ("lab_code_1", "collecting_institution_code_1"), + "NCIT:C101703": ("lab_code_2", "collecting_institution_code_2"), + "OBI:0001890": ("lab_email", "collecting_institution_email"), + "NCIT:C40978": ("lab_phone", "collecting_institution_phone"), + "GENEPIO:0001158": ("address", "collecting_institution_address"), + "GENEPIO:0001803": ("autonom_cod", "autonom_cod"), + "GENEPIO:0001185": ("geo_loc_state", "geo_loc_state"), + "GENEPIO:0001189": ("geo_loc_city", "geo_loc_city"), + "NCIT:C25621": ("post_code", "post_code"), + "mesh:D009935": ("dep_func", "dep_func"), + "NCIT:C93878": ("center_class_code", "center_class_code"), + "NCIT:C188820": ("lab_function", "collecting_institution_function"), + "EFO:0005020": ("lab_geo_loc_latitude", "lab_geo_loc_latitude"), + "EFO:0005021": ("lab_geo_loc_longitude", "lab_geo_loc_longitude"), + "OBI:0001620": ("geo_loc_latitude", "geo_loc_latitude"), + "OBI:0001621": ("geo_loc_longitude", "geo_loc_longitude"), +} diff --git a/wetlab/api/urls.py b/wetlab/api/urls.py index 871a2dfb..b4c892ca 100644 --- a/wetlab/api/urls.py +++ b/wetlab/api/urls.py @@ -29,4 +29,9 @@ name="summarize_data_information", ), path("update-lab", views.update_lab, name="update_lab"), + path( + "lab-request-mapping", + views.get_lab_request_mapping, + name="get_lab_request_mapping", + ), ] diff --git a/wetlab/api/utils/sample.py b/wetlab/api/utils/sample.py index 062964b6..420f2c97 100644 --- a/wetlab/api/utils/sample.py +++ b/wetlab/api/utils/sample.py @@ -2,6 +2,7 @@ import core.models import core.utils.samples +import core.core_config import wetlab.api.serializers import wetlab.config @@ -353,31 +354,15 @@ def split_sample_data(data): lab_data["lab_unit"] = "" lab_data["lab_contact_name"] = "" lab_data["lab_phone"] = "" - lab_data_fields = [ - ("lab_email", "collecting_institution_email"), - ("address", "collecting_institution_address"), - ("geo_loc_city", "geo_loc_city"), - ("geo_loc_state", "geo_loc_state"), - ("geo_loc_latitude", "geo_loc_latitude"), - ("geo_loc_longitude", "geo_loc_longitude"), - ] + lab_req_mapping = core.core_config.LAB_REQUEST_ONTOLOGY_MAP + lab_data_fields = lab_req_mapping.values() for l_data, i_data in lab_data_fields: try: lab_data[l_data] = data[i_data] except KeyError: - lab_data[l_data] = "" - - """ - lab_data["lab_email"] = data["collecting_institution_email"] - lab_data["address"] = data["collecting_institution_address"] - lab_data["geo_loc_city"] = data["geo_loc_city"] - lab_data["geo_loc_state"] = data["geo_loc_state"] - lab_data["geo_loc_latitude"] = data["geo_loc_latitude"] - lab_data["geo_loc_longitude"] = data["geo_loc_longitude"] - """ + lab_data[l_data] = data.get(l_data, "") split_data["lab_data"] = lab_data - return split_data diff --git a/wetlab/api/views.py b/wetlab/api/views.py index b20bd470..0ce09a93 100644 --- a/wetlab/api/views.py +++ b/wetlab/api/views.py @@ -13,6 +13,7 @@ from rest_framework.response import Response import core.models +import core.core_config import wetlab.api.serializers import wetlab.api.utils.lab import wetlab.api.utils.sample @@ -182,7 +183,13 @@ def create_sample_data(request): if isinstance(data, QueryDict): data = data.dict() if "sample_name" not in data or "sample_project" not in data: - return Response(status=status.HTTP_400_BAD_REQUEST) + return Response( + { + "ERROR": "Missing fields `sample_name` or `sample_project` in data", + "data": data, + }, + status=status.HTTP_400_BAD_REQUEST, + ) not_allowed_sample_names = [] allowed_sample_repeat = ( False @@ -228,26 +235,19 @@ def create_sample_data(request): return Response(error, status=status.HTTP_400_BAD_REQUEST) split_data = wetlab.api.utils.sample.split_sample_data(data) if not isinstance(split_data, dict): - return Response(split_data, status=status.HTTP_400_BAD_REQUEST) + return Response( + {"ERROR": "Error splitting data", "data": split_data}, + status=status.HTTP_400_BAD_REQUEST, + ) apps_name = __package__.split(".")[0] inst_req_sample = wetlab.api.utils.sample.include_instances_in_sample( split_data["s_data"], split_data["lab_data"], apps_name ) - required_submit_inst_fieldmap = { - "submitting_institution": "lab_name", - "submitting_institution_email": "lab_email", - "submitting_institution_address": "address", - } - if all(k in data for k in required_submit_inst_fieldmap.keys()): - submit_inst_data = split_data["lab_data"].copy() - for field, keymap in required_submit_inst_fieldmap.items(): - submit_inst_data[keymap] = data.get(field, "") - submit_inst_data["lab_name_coding"] = "".join( - [x[0] for x in data["lab_name"].strip().split(" ")] - ) - wetlab.api.utils.sample.create_new_laboratory(submit_inst_data) if not isinstance(inst_req_sample, dict): - return Response(inst_req_sample, status=status.HTTP_400_BAD_REQUEST) + return Response( + {"ERROR": "Error including data", "data": inst_req_sample}, + status=status.HTTP_400_BAD_REQUEST, + ) split_data["s_data"] = inst_req_sample split_data["s_data"]["sample_user"] = request.user.pk # Adding coding for sample @@ -261,7 +261,11 @@ def create_sample_data(request): ) if not sample_serializer.is_valid(): return Response( - sample_serializer.errors, status=status.HTTP_400_BAD_REQUEST + { + "ERROR": f"Error serializing sample {data['sample_name']}", + "data": sample_serializer.errors, + }, + status=status.HTTP_400_BAD_REQUEST, ) new_sample_id = sample_serializer.save().get_sample_id() for d_field in split_data["p_data"]: @@ -271,12 +275,23 @@ def create_sample_data(request): ) if not s_project_serializer.is_valid(): return Response( - s_project_serializer.errors, status=status.HTTP_400_BAD_REQUEST + { + "ERROR": "Error serializing project", + "data": s_project_serializer.errors, + }, + status=status.HTTP_400_BAD_REQUEST, ) s_project_serializer.save() - return Response("Successful upload information", status=status.HTTP_201_CREATED) - return Response(status=status.HTTP_400_BAD_REQUEST) + return Response( + {"message": "Successful upload information", "data": split_data["s_data"]}, + status=status.HTTP_201_CREATED, + ) + else: + return Response( + {"ERROR": f"Request method must be POST, received {request.method}"}, + status=status.HTTP_400_BAD_REQUEST, + ) @swagger_auto_schema( @@ -419,6 +434,18 @@ def sample_project_fields(request): return Response(status=status.HTTP_400_BAD_REQUEST) +@swagger_auto_schema( + method="get", + operation_description="Use this request to get the fields used to fill lab_request model", + manual_parameters=[laboratory], +) +@api_view(["GET"]) +def get_lab_request_mapping(request): + return Response( + {"data": core.core_config.LAB_REQUEST_ONTOLOGY_MAP}, status=status.HTTP_200_OK + ) + + @swagger_auto_schema(method="get", manual_parameters=[laboratory]) @api_view(["GET"]) def get_lab_information_contact(request):