forked from enviPath/enviPy
Compare commits
14 Commits
99c796813a
...
3114e2df4c
| Author | SHA1 | Date | |
|---|---|---|---|
| 3114e2df4c | |||
| a23cb5bd5f | |||
| d52d3b0a65 | |||
| 2b1d0099cd | |||
| 31b4784ecd | |||
| 19840edc1e | |||
| be5ee1d1d7 | |||
| 20fd949dfd | |||
| c9b643fe6e | |||
| 1a9f1cf9af | |||
| c7c7e17e43 | |||
| 674e10c7fa | |||
| 8079b80d57 | |||
| 76e63fda2c |
26
epapi/v1/endpoints/joblogs.py
Normal file
26
epapi/v1/endpoints/joblogs.py
Normal file
@ -0,0 +1,26 @@
|
||||
from django.conf import settings as s
|
||||
from ninja import Router
|
||||
from ninja_extra.pagination import paginate
|
||||
|
||||
from epdb.models import JobLog
|
||||
from ..pagination import EnhancedPageNumberPagination
|
||||
from ..schemas import JobLogOutSchema
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@router.get("/joblog/", response=EnhancedPageNumberPagination.Output[JobLogOutSchema])
|
||||
@paginate(
|
||||
EnhancedPageNumberPagination,
|
||||
page_size=s.API_PAGINATION_DEFAULT_PAGE_SIZE,
|
||||
)
|
||||
def list_all_joblogs(request):
|
||||
"""
|
||||
List all JobLogs from reviewed packages.
|
||||
"""
|
||||
current_user = request.user
|
||||
|
||||
if current_user.is_superuser:
|
||||
return JobLog.objects.all().order_by("-created")
|
||||
else:
|
||||
return JobLog.objects.filter(user=current_user).order_by("-created")
|
||||
@ -15,6 +15,7 @@ from .endpoints import (
|
||||
additional_information,
|
||||
settings,
|
||||
groups,
|
||||
joblogs,
|
||||
)
|
||||
|
||||
# Main router with authentication
|
||||
@ -37,6 +38,7 @@ router.add_router("", structure.router)
|
||||
router.add_router("", additional_information.router)
|
||||
router.add_router("", settings.router)
|
||||
router.add_router("", groups.router)
|
||||
router.add_router("", joblogs.router)
|
||||
|
||||
if s.IUCLID_EXPORT_ENABLED:
|
||||
from epiuclid.api import router as iuclid_router
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
from ninja import FilterSchema, FilterLookup, Schema
|
||||
from datetime import datetime
|
||||
from typing import Annotated, Optional, List, Dict, Any
|
||||
from uuid import UUID
|
||||
|
||||
from django.urls import reverse
|
||||
from ninja import Field, FilterSchema, FilterLookup, Schema
|
||||
|
||||
|
||||
# Filter schema for query parameters
|
||||
class ReviewStatusFilter(FilterSchema):
|
||||
@ -133,3 +136,23 @@ class GroupOutSchema(Schema):
|
||||
url: str = ""
|
||||
name: str
|
||||
description: str
|
||||
|
||||
|
||||
class SimpleUserOutSchema(Schema):
|
||||
uuid: UUID
|
||||
url: str
|
||||
name: str = Field(alias="username")
|
||||
|
||||
|
||||
class JobLogOutSchema(Schema):
|
||||
user: SimpleUserOutSchema
|
||||
id: UUID = Field(alias="task_id")
|
||||
url: str
|
||||
name: str = Field(alias="job_name")
|
||||
created: datetime = Field(alias="created")
|
||||
status: str = Field(alias="status")
|
||||
done: Optional[datetime] = Field(None, alias="done_at")
|
||||
|
||||
@staticmethod
|
||||
def resolve_url(obj):
|
||||
return reverse("job detail", kwargs={"job_uuid": obj.task_id})
|
||||
|
||||
@ -439,23 +439,50 @@ class PackageSchema(Schema):
|
||||
|
||||
@staticmethod
|
||||
def resolve_readers(obj: Package):
|
||||
users = User.objects.filter(
|
||||
id__in=UserPackagePermission.objects.filter(
|
||||
package=obj, permission=UserPackagePermission.READ[0]
|
||||
).values_list("user", flat=True)
|
||||
).distinct()
|
||||
readers = []
|
||||
|
||||
return [{u.id: u.get_name()} for u in users]
|
||||
user_ids = UserPackagePermission.objects.filter(package=obj).values_list("user", flat=True)
|
||||
|
||||
users = User.objects.filter(id__in=user_ids).distinct()
|
||||
|
||||
for u in users:
|
||||
readers.append({"id": str(u.url), "identifier": "user", "name": u.get_name()})
|
||||
|
||||
group_ids = GroupPackagePermission.objects.filter(package=obj).values_list(
|
||||
"group", flat=True
|
||||
)
|
||||
|
||||
groups = Group.objects.filter(id__in=group_ids).distinct()
|
||||
|
||||
for g in groups:
|
||||
readers.append({"id": str(g.url), "identifier": "group", "name": g.get_name()})
|
||||
|
||||
return readers
|
||||
|
||||
@staticmethod
|
||||
def resolve_writers(obj: Package):
|
||||
users = User.objects.filter(
|
||||
id__in=UserPackagePermission.objects.filter(
|
||||
package=obj, permission=UserPackagePermission.WRITE[0]
|
||||
).values_list("user", flat=True)
|
||||
).distinct()
|
||||
writers = []
|
||||
|
||||
return [{u.id: u.get_name()} for u in users]
|
||||
user_ids = UserPackagePermission.objects.filter(
|
||||
package=obj,
|
||||
permission__in=[UserPackagePermission.WRITE[0], UserPackagePermission.ALL[0]],
|
||||
).values_list("user", flat=True)
|
||||
|
||||
users = User.objects.filter(id__in=user_ids).distinct()
|
||||
|
||||
for u in users:
|
||||
writers.append({"id": str(u.url), "identifier": "user", "name": u.get_name()})
|
||||
|
||||
group_ids = GroupPackagePermission.objects.filter(
|
||||
package=obj, permission=[UserPackagePermission.WRITE[0], UserPackagePermission.ALL[0]]
|
||||
).values_list("group", flat=True)
|
||||
|
||||
groups = Group.objects.filter(id__in=group_ids).distinct()
|
||||
|
||||
for g in groups:
|
||||
writers.append({"id": str(g.url), "identifier": "group", "name": g.get_name()})
|
||||
|
||||
return writers
|
||||
|
||||
@staticmethod
|
||||
def resolve_review_comment(obj):
|
||||
@ -872,6 +899,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}"
|
||||
)
|
||||
@ -1398,6 +1446,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"
|
||||
@ -1541,28 +1590,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}")
|
||||
@ -1767,6 +1844,29 @@ def create_package_pathway(
|
||||
return 403, {"message": str(e)}
|
||||
|
||||
|
||||
@router.post("/package/{uuid:package_uuid}/pathway/{uuid:pathway_uuid}")
|
||||
def update_pathway(request, package_uuid, pathway_uuid):
|
||||
try:
|
||||
p = get_package_for_write(request.user, package_uuid)
|
||||
|
||||
if request.POST.get("scenario"):
|
||||
pw = Pathway.objects.get(package=p, uuid=pathway_uuid)
|
||||
scen = Scenario.objects.get(package=p, url=request.POST.get("scenario"))
|
||||
|
||||
pw.scenarios.add(scen)
|
||||
pw.save()
|
||||
|
||||
return redirect(f"{pw.url}")
|
||||
|
||||
else:
|
||||
return 400, {"message": "No scenario specified!"}
|
||||
|
||||
except ValueError:
|
||||
return 403, {
|
||||
"message": f"Deleting Pathway with id {pathway_uuid} failed due to insufficient rights!"
|
||||
}
|
||||
|
||||
|
||||
@router.delete("/package/{uuid:package_uuid}/pathway/{uuid:pathway_uuid}")
|
||||
def delete_pathway(request, package_uuid, pathway_uuid):
|
||||
try:
|
||||
@ -2078,6 +2178,10 @@ def add_pathway_edge(request, package_uuid, pathway_uuid, e: Form[CreateEdge]):
|
||||
for pr in e.products.split(","):
|
||||
products.append(Node.objects.get(pathway=pw, url=pr.strip()))
|
||||
|
||||
multi_step = None
|
||||
if e.multistep and e.multistep.strip() == "true":
|
||||
multi_step = True
|
||||
|
||||
new_e = Edge.create(
|
||||
pathway=pw,
|
||||
start_nodes=educts,
|
||||
@ -2085,6 +2189,7 @@ def add_pathway_edge(request, package_uuid, pathway_uuid, e: Form[CreateEdge]):
|
||||
rule=None,
|
||||
name=None,
|
||||
description=e.edgeReason,
|
||||
multi_step=multi_step,
|
||||
)
|
||||
|
||||
# Update depths as sideeffect of above operation
|
||||
|
||||
@ -1703,7 +1703,7 @@ class Reaction(
|
||||
if name is not None and name.strip() != "":
|
||||
r.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
if description is not None and name.strip() != "":
|
||||
if description is not None and description.strip() != "":
|
||||
r.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
r.multi_step = multi_step
|
||||
@ -2200,6 +2200,7 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix
|
||||
|
||||
depth_map = {}
|
||||
depth_map[0] = list()
|
||||
processed = set()
|
||||
|
||||
for n in self.nodes:
|
||||
num_parents = in_count[str(n.uuid)]
|
||||
@ -2222,10 +2223,12 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix
|
||||
|
||||
unique_next_level = set()
|
||||
for n in level_nodes:
|
||||
processed.add(n)
|
||||
for e in self.edges:
|
||||
if n in e.start_nodes.all():
|
||||
for p in e.end_nodes.all():
|
||||
unique_next_level.add(p)
|
||||
if p not in processed:
|
||||
unique_next_level.add(p)
|
||||
|
||||
if len(unique_next_level) > 0:
|
||||
depth_map[i + 1] = list(unique_next_level)
|
||||
@ -2463,6 +2466,8 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin)
|
||||
rule: Optional[Rule] = None,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
*args,
|
||||
**kwargs,
|
||||
):
|
||||
e = Edge()
|
||||
e.pathway = pathway
|
||||
@ -2492,7 +2497,7 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin)
|
||||
educts=[n.default_node_label for n in e.start_nodes.all()],
|
||||
products=[n.default_node_label for n in e.end_nodes.all()],
|
||||
rules=rule,
|
||||
multi_step=False,
|
||||
multi_step=kwargs.get("multi_step", False),
|
||||
)
|
||||
|
||||
e.edge_label = r
|
||||
@ -4500,18 +4505,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:
|
||||
|
||||
@ -3113,12 +3113,21 @@ def jobs(request):
|
||||
{"Home": s.SERVER_URL},
|
||||
{"Jobs": s.SERVER_URL + "/jobs"},
|
||||
]
|
||||
if current_user.is_superuser:
|
||||
context["jobs"] = JobLog.objects.all().order_by("-created")
|
||||
else:
|
||||
context["jobs"] = JobLog.objects.filter(user=current_user).order_by("-created")
|
||||
# if current_user.is_superuser:
|
||||
# context["jobs"] = JobLog.objects.all().order_by("-created")
|
||||
# else:
|
||||
# context["jobs"] = JobLog.objects.filter(user=current_user).order_by("-created")
|
||||
|
||||
return render(request, "collections/joblog.html", context)
|
||||
# Context for paginated template
|
||||
context["entity_type"] = "joblog"
|
||||
context["api_endpoint"] = f"{s.SERVER_PATH}/api/v1/joblog/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "joblog"
|
||||
context["list_mode"] = "combined"
|
||||
|
||||
return render(request, "collections/joblog_paginated.html", context)
|
||||
|
||||
# return render(request, "collections/joblog.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
job_name = request.POST.get("job-name")
|
||||
|
||||
@ -463,7 +463,7 @@ function draw(pathway, elem) {
|
||||
// TODO needs to be generic once we store it as AddInf
|
||||
for (var s of n.predicted_properties["PepperPrediction"]) {
|
||||
if (s["mean"] != null) {
|
||||
tempContent += "<b>DT50 predicted via Pepper:</b> " + s["mean"].toFixed(2) + "<br>"
|
||||
tempContent += "<b>DT50 predicted via Pepper:</b> " + s["mean"].toFixed(2) + " days<br>"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
102
templates/collections/_joblog_paginated_list_partial.html
Normal file
102
templates/collections/_joblog_paginated_list_partial.html
Normal file
@ -0,0 +1,102 @@
|
||||
{# Partial for paginated list content - expects to be inside a remotePaginatedList Alpine.js context #}
|
||||
{# Variables: empty_text (string), show_review_badge (bool), always_show_badge (bool) #}
|
||||
{% load envipytags %}
|
||||
{# Loading state #}
|
||||
<div
|
||||
x-show="isLoading"
|
||||
class="mx-auto flex h-32 w-32 items-center justify-center"
|
||||
>
|
||||
{% include "components/loading-spinner.html" %}
|
||||
</div>
|
||||
|
||||
{# Error state #}
|
||||
<div
|
||||
x-show="!isLoading && error"
|
||||
class="alert alert-error/50 text-sm"
|
||||
x-text="error"
|
||||
></div>
|
||||
|
||||
{# Content #}
|
||||
<template x-if="!isLoading && !error">
|
||||
<div>
|
||||
{# Empty state #}
|
||||
<div
|
||||
x-show="totalItems === 0"
|
||||
class="text-base-content/70 py-8 text-center"
|
||||
>
|
||||
<p>No {{ empty_text|default:"items" }} found.</p>
|
||||
</div>
|
||||
|
||||
{# Items list #}
|
||||
<ul class="menu bg-base-100 rounded-box w-full" x-show="totalItems > 0">
|
||||
<table class="table-zebra table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
<th>Queued At</th>
|
||||
<th>Done At</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="obj in paginatedItems" :key="obj.url">
|
||||
<tr>
|
||||
<td>
|
||||
<a :href="obj.user.url"><span x-text="obj.user.name"></span></a>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<a :href="obj.url"><span x-text="obj.id"></span></a>
|
||||
</td>
|
||||
<td><span x-text="obj.name"></span></td>
|
||||
<td><span x-text="obj.status"></span></td>
|
||||
<td><span x-text="obj.created"></span></td>
|
||||
<td><span x-text="obj.done"></span></td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</ul>
|
||||
|
||||
{# Pagination controls #}
|
||||
<div
|
||||
x-show="totalPages > 1"
|
||||
class="mt-4 flex items-center justify-between px-2"
|
||||
>
|
||||
<span class="text-base-content/70 text-sm">
|
||||
Showing <span x-text="showingStart"></span>-<span
|
||||
x-text="showingEnd"
|
||||
></span>
|
||||
of <span x-text="totalItems"></span>
|
||||
</span>
|
||||
<div class="join">
|
||||
<button
|
||||
class="join-item btn btn-sm"
|
||||
:disabled="currentPage === 1"
|
||||
@click="prevPage()"
|
||||
>
|
||||
«
|
||||
</button>
|
||||
<template x-for="item in pageNumbers" :key="item.key">
|
||||
<button
|
||||
class="join-item btn btn-sm"
|
||||
:class="{ 'btn-active': item.page === currentPage }"
|
||||
:disabled="item.isEllipsis"
|
||||
@click="!item.isEllipsis && goToPage(item.page)"
|
||||
x-text="item.page"
|
||||
></button>
|
||||
</template>
|
||||
<button
|
||||
class="join-item btn btn-sm"
|
||||
:disabled="currentPage === totalPages"
|
||||
@click="nextPage()"
|
||||
>
|
||||
»
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
13
templates/collections/joblog_paginated.html
Normal file
13
templates/collections/joblog_paginated.html
Normal file
@ -0,0 +1,13 @@
|
||||
{% extends "collections/paginated_base.html" %}
|
||||
|
||||
{% block page_title %}Jobs{% endblock %}
|
||||
|
||||
{% block action_button %}
|
||||
{% endblock action_button %}
|
||||
|
||||
{% block action_modals %}
|
||||
{% endblock action_modals %}
|
||||
|
||||
{% block description %}
|
||||
<p>List of Jobs submitted.</p>
|
||||
{% endblock description %}
|
||||
@ -37,7 +37,11 @@
|
||||
perPage: {{ per_page|default:50 }}
|
||||
})"
|
||||
>
|
||||
{% include "collections/_paginated_list_partial.html" with empty_text=list_title|default:"items" show_review_badge=True %}
|
||||
{% if entity_type == 'joblog' %}
|
||||
{% include "collections/_joblog_paginated_list_partial.html" with empty_text=list_title|default:"items" show_review_badge=True %}
|
||||
{% else %}
|
||||
{% include "collections/_paginated_list_partial.html" with empty_text=list_title|default:"items" show_review_badge=True %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
{# ===== TABBED MODE: Reviewed/Unreviewed tabs (default) ===== #}
|
||||
|
||||
@ -125,6 +125,7 @@ from envipy_additional_information.parsers import (
|
||||
LiquidMatrixSourceParser,
|
||||
OxygenUptakeRateParser,
|
||||
InitiatingOrganismParser,
|
||||
PFASConfidenceParser,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -141,7 +142,7 @@ def get_parameter(request, paramname):
|
||||
res = request.POST.get(paramname)
|
||||
if res is not None and res.strip() != "":
|
||||
return res
|
||||
return ValueError("Not all parameters are set!")
|
||||
raise ValueError("Not all parameters are set!")
|
||||
|
||||
|
||||
def get_parameter_or_empty_string(request, paramname):
|
||||
@ -673,7 +674,8 @@ def build_additional_information_from_request(request, type_):
|
||||
elif type_ == "studywst":
|
||||
# study_wst_cond = get_parameter(request, "studywstcond")
|
||||
raise ValueError("studywstcond is not yet implemented")
|
||||
|
||||
elif type_ == "pfasconfidence":
|
||||
return PFASConfidenceParser.from_string(get_parameter(request, "level"))
|
||||
else:
|
||||
raise ValueError(f"No corresponding AdditionalInformation for {type_} found!")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user