From c7c7e17e43c0e36eab8a0505d1f7bc0e690c5d2c Mon Sep 17 00:00:00 2001 From: jebus Date: Thu, 28 May 2026 01:41:28 +1200 Subject: [PATCH] [Feature] Implement legacy endpoints to enable copy via python client (#400) Co-authored-by: Tim Lorsbach Reviewed-on: https://git.envipath.com/enviPath/enviPy/pulls/400 --- epdb/legacy_api.py | 84 ++++++++++++++++++++++++++++++++++++---------- epdb/models.py | 12 ++++--- 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/epdb/legacy_api.py b/epdb/legacy_api.py index 952d4d5d..64f5f24b 100644 --- a/epdb/legacy_api.py +++ b/epdb/legacy_api.py @@ -826,6 +826,27 @@ def delete_compound(request, package_uuid, compound_uuid): } +class CreateCompoundStructure(Schema): + smiles: str + name: str | None = None + description: str | None = None + inchi: str | None = None + molfile: str | None = None + + +@router.post("/package/{uuid:package_uuid}/compound/{uuid:compound_uuid}/structure") +def create_package_compound_structure( + request, package_uuid, compound_uuid, structure: Form[CreateCompoundStructure] +): + try: + p = get_package_for_write(request.user, package_uuid) + c = Compound.objects.get(package=p, uuid=compound_uuid) + cs = CompoundStructure.create(c, structure.smiles, structure.name, structure.description) + return redirect(cs.url) + except ValueError as e: + return 400, {"message": str(e)} + + @router.delete( "/package/{uuid:package_uuid}/compound/{uuid:compound_uuid}/structure/{uuid:structure_uuid}" ) @@ -1352,6 +1373,7 @@ class ScenarioSchema(Schema): aliases: List[str] = Field([], alias="aliases") collection: Dict["str", List[Dict[str, Any]]] = Field([], alias="collection") collectionID: Optional[str] = None + date: str = Field(None, alias="scenario_date") description: str = Field(None, alias="description") id: str = Field(None, alias="url") identifier: str = "scenario" @@ -1495,28 +1517,56 @@ def create_package_additional_information(request, package_uuid): scen = request.POST.get("scenario") scenario = Scenario.objects.get(package=p, url=scen) - url_parser = EPDBURLParser(request.POST.get("attach_obj")) - attach_obj = url_parser.get_object() + if request.POST.get("adInfoTypes[]"): + url_parser = EPDBURLParser(request.POST.get("attach_obj")) + attach_obj = url_parser.get_object() - if not hasattr(attach_obj, "additional_information"): - raise ValueError("Can't attach additional information to this object!") + if not hasattr(attach_obj, "additional_information"): + raise ValueError("Can't attach additional information to this object!") - if not attach_obj.url.startswith(p.url): - raise ValueError( - "Additional Information can only be set to objects stored in the same package!" - ) + if not attach_obj.url.startswith(p.url): + raise ValueError( + "Additional Information can only be set to objects stored in the same package!" + ) - types = request.POST.get("adInfoTypes[]", "").split(",") + types = request.POST.get("adInfoTypes[]", "").split(",") - for t in types: - ai = build_additional_information_from_request(request, t) + for t in types: + ai = build_additional_information_from_request(request, t) - AdditionalInformation.create( - p, - ai, - scenario=scenario, - content_object=attach_obj, - ) + AdditionalInformation.create( + p, + ai, + scenario=scenario, + content_object=attach_obj, + ) + + elif request.POST.get("ais"): + import json + + parsed_ais = json.loads(request.POST.get("ais")) + + for ai_type, ais in parsed_ais.items(): + for ai in ais: + attach_obj = None + if ai.get("related"): + url_parser = EPDBURLParser(ai.get("related").get("url")) + attach_obj = url_parser.get_object() + + if not hasattr(attach_obj, "additional_information"): + raise ValueError("Can't attach additional information to this object!") + + if not attach_obj.url.startswith(p.url): + raise ValueError( + "Additional Information can only be set to objects stored in the same package!" + ) + + AdditionalInformation.create( + p, + AdditionalInformation.from_dict(ai_type, ai), + scenario=scenario, + content_object=attach_obj, + ) # TODO implement additional information endpoint ? return redirect(f"{scenario.url}") diff --git a/epdb/models.py b/epdb/models.py index 9b8bd633..1d44357c 100644 --- a/epdb/models.py +++ b/epdb/models.py @@ -4492,18 +4492,22 @@ class AdditionalInformation(models.Model): return f"{self.scenario.url}/additional-information/{self.uuid}" - def get(self) -> "EnviPyModel": + @staticmethod + def from_dict(ai_type: str, ai_data: Dict[str, Any]): from envipy_additional_information import registry MAPPING = {c.__name__: c for c in registry.list_models().values()} try: - inst = MAPPING[self.type](**self.data) + inst = MAPPING[ai_type](**ai_data) except Exception as e: - print(f"Error loading {self.type}: {e}") + print(f"Error loading {ai_type}: {e}") raise e - inst.__dict__["uuid"] = str(self.uuid) + return inst + def get(self) -> "EnviPyModel": + inst = AdditionalInformation.from_dict(self.type, self.data) + inst.__dict__["uuid"] = str(self.uuid) return inst def __str__(self) -> str: