[Feature] Scenario and Additional Information creation via enviPath-python, Add Half Lifes to API Output, Fix source/target ids in legacy API (#340)

Co-authored-by: Tim Lorsbach <tim@lorsba.ch>
Reviewed-on: enviPath/enviPy#340
This commit is contained in:
2026-03-06 07:20:18 +13:00
parent 81cc612e69
commit 6e00926371
3 changed files with 795 additions and 32 deletions

View File

@ -3,7 +3,7 @@ from typing import Any, Dict, List, Optional
import nh3
from django.conf import settings as s
from django.contrib.auth import get_user_model
from django.http import HttpResponse
from django.http import HttpResponse, JsonResponse
from django.shortcuts import redirect
from ninja import Field, Form, Query, Router, Schema
from ninja.security import SessionAuth
@ -558,21 +558,42 @@ class CompoundSchema(Schema):
@staticmethod
def resolve_halflifes(obj: Compound):
return []
res = []
for scen, hls in obj.half_lifes().items():
for hl in hls:
res.append(
{
"hl": str(hl.dt50),
"hlComment": hl.comment,
"hlFit": hl.fit,
"hlModel": hl.model,
"scenarioId": scen.url,
"scenarioName": scen.name,
"scenarioType": scen.scenario_type,
"source": hl.source,
}
)
return res
@staticmethod
def resolve_pubchem_compound_references(obj: Compound):
# TODO
return []
@staticmethod
def resolve_pathway_scenarios(obj: Compound):
return [
{
"scenarioId": "https://envipath.org/package/5882df9c-dae1-4d80-a40e-db4724271456/scenario/cd8350cd-4249-4111-ba9f-4e2209338501",
"scenarioName": "Fritz, R. & Brauner, A. (1989) - (00004)",
"scenarioType": "Soil",
}
]
res = []
for pw in obj.related_pathways:
for scen in pw.scenarios.all():
res.append(
{
"scenarioId": scen.url,
"scenarioName": scen.name,
"scenarioType": scen.scenario_type,
}
)
return res
class CompoundStructureSchema(Schema):
@ -625,7 +646,22 @@ class CompoundStructureSchema(Schema):
@staticmethod
def resolve_halflifes(obj: CompoundStructure):
return []
res = []
for scen, hls in obj.half_lifes().items():
for hl in hls:
res.append(
{
"hl": str(hl.dt50),
"hlComment": hl.comment,
"hlFit": hl.fit,
"hlModel": hl.model,
"scenarioId": scen.url,
"scenarioName": scen.name,
"scenarioType": scen.scenario_type,
"source": hl.source,
}
)
return res
@staticmethod
def resolve_pubchem_compound_references(obj: CompoundStructure):
@ -633,13 +669,18 @@ class CompoundStructureSchema(Schema):
@staticmethod
def resolve_pathway_scenarios(obj: CompoundStructure):
return [
{
"scenarioId": "https://envipath.org/package/5882df9c-dae1-4d80-a40e-db4724271456/scenario/cd8350cd-4249-4111-ba9f-4e2209338501",
"scenarioName": "Fritz, R. & Brauner, A. (1989) - (00004)",
"scenarioType": "Soil",
}
]
res = []
for pw in obj.related_pathways:
for scen in pw.scenarios.all():
res.append(
{
"scenarioId": scen.url,
"scenarioName": scen.name,
"scenarioType": scen.scenario_type,
}
)
return res
class CompoundStructureWrapper(Schema):
@ -1327,9 +1368,42 @@ def get_package_scenario(request, package_uuid, scenario_uuid):
}
@router.post("/package/{uuid:package_uuid}/scenario")
@router.post("/package/{uuid:package_uuid}/scenario", response={200: str | Any, 403: Error})
def create_package_scenario(request, package_uuid):
pass
from utilities.legacy import build_additional_information_from_request
try:
p = get_package_for_write(request.user, package_uuid)
scen_date = None
date_year = request.POST.get("dateYear")
date_month = request.POST.get("dateMonth")
date_day = request.POST.get("dateDay")
if date_year:
scen_date = date_year
if date_month:
scen_date += f"-{date_month}"
if date_day:
scen_date += f"-{date_day}"
name = request.POST.get("studyname")
description = request.POST.get("studydescription")
study_type = request.POST.get("type")
ais = []
types = request.POST.getlist("adInfoTypes[]")
for t in types:
ais.append(build_additional_information_from_request(request, t))
new_s = Scenario.create(p, name, description, scen_date, study_type, ais)
return JsonResponse({"scenarioLocation": new_s.url})
except ValueError:
return 403, {
"message": f"Getting Package with id {package_uuid} failed due to insufficient rights!"
}
@router.delete("/package/{uuid:package_uuid}/scenario")
@ -1376,8 +1450,8 @@ class PathwayEdge(Schema):
pseudo: bool = False
rule: Optional[str] = Field(None, alias="rule")
scenarios: List[SimpleScenario] = Field([], alias="scenarios")
source: int = -1
target: int = -1
source: int = Field(-1)
target: int = Field(-1)
@staticmethod
def resolve_rule(obj: Edge):
@ -1440,9 +1514,9 @@ class PathwaySchema(Schema):
isIncremental: bool = Field(None, alias="is_incremental")
isPredicted: bool = Field(None, alias="is_predicted")
lastModified: int = Field(None, alias="last_modified")
links: List[PathwayEdge] = Field([], alias="edges")
links: List[PathwayEdge] = Field([])
name: str = Field(None, alias="name")
nodes: List[PathwayNode] = Field([], alias="nodes")
nodes: List[PathwayNode] = Field([])
pathwayName: str = Field(None, alias="name")
reviewStatus: str = Field(None, alias="review_status")
scenarios: List["SimpleScenario"] = Field([], alias="scenarios")
@ -1464,6 +1538,14 @@ class PathwaySchema(Schema):
def resolve_last_modified(obj: Pathway):
return int(obj.modified.timestamp())
@staticmethod
def resolve_links(obj: Pathway):
return obj.d3_json().get("links", [])
@staticmethod
def resolve_nodes(obj: Pathway):
return obj.d3_json().get("nodes", [])
@router.get("/pathway", response={200: PathwayWrapper, 403: Error})
def get_pathways(request):
@ -1507,8 +1589,8 @@ class CreatePathway(Schema):
selectedSetting: str | None = None
@router.post("/package/{uuid:package_uuid}/pathway")
def create_pathway(
@router.post("/package/{uuid:package_uuid}/pathway", response={200: Any, 403: Error})
def create_package_pathway(
request,
package_uuid,
pw: Form[CreatePathway],
@ -1516,9 +1598,6 @@ def create_pathway(
try:
p = get_package_for_write(request.user, package_uuid)
if not PackageManager.writable(request.user, p):
raise ValueError("You do not have the rights to create a Pathway!")
stand_smiles = FormatConverter.standardize(pw.smilesinput.strip(), remove_stereo=True)
new_pw = Pathway.create(p, stand_smiles, name=pw.name, description=pw.description)
@ -1546,7 +1625,7 @@ def create_pathway(
return redirect(new_pw.url)
except ValueError as e:
return 400, {"message": str(e)}
return 403, {"message": str(e)}
@router.delete("/package/{uuid:package_uuid}/pathway/{uuid:pathway_uuid}")