forked from enviPath/enviPy
[Fix] UI bugs, Registrations Mail, BTRules Popup, Legacy API fixes (#309)
Co-authored-by: Tim Lorsbach <tim@lorsba.ch> Reviewed-on: enviPath/enviPy#309
This commit is contained in:
@ -48,11 +48,6 @@ runs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
uv run python scripts/pnpm_wrapper.py install
|
uv run python scripts/pnpm_wrapper.py install
|
||||||
cat << 'EOF' > pnpm-workspace.yaml
|
|
||||||
onlyBuiltDependencies:
|
|
||||||
- '@parcel/watcher'
|
|
||||||
- '@tailwindcss/oxide'
|
|
||||||
EOF
|
|
||||||
uv run python scripts/pnpm_wrapper.py run build
|
uv run python scripts/pnpm_wrapper.py run build
|
||||||
|
|
||||||
- name: Wait for Postgres
|
- name: Wait for Postgres
|
||||||
|
|||||||
@ -212,7 +212,7 @@ def get_user(request, user_uuid):
|
|||||||
|
|
||||||
|
|
||||||
class GroupMember(Schema):
|
class GroupMember(Schema):
|
||||||
id: str = Field(None, alias="url")
|
id: str
|
||||||
identifier: str
|
identifier: str
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ class GroupSchema(Schema):
|
|||||||
members: List[GroupMember] = Field([], alias="members")
|
members: List[GroupMember] = Field([], alias="members")
|
||||||
name: str = Field(None, alias="name")
|
name: str = Field(None, alias="name")
|
||||||
ownerid: str = Field(None, alias="owner.url")
|
ownerid: str = Field(None, alias="owner.url")
|
||||||
ownername: str = Field(None, alias="owner.name")
|
ownername: str = Field(None, alias="owner.get_name")
|
||||||
packages: List["SimplePackage"] = Field([], alias="packages")
|
packages: List["SimplePackage"] = Field([], alias="packages")
|
||||||
readers: List[GroupMember] = Field([], alias="readers")
|
readers: List[GroupMember] = Field([], alias="readers")
|
||||||
writers: List[GroupMember] = Field([], alias="writers")
|
writers: List[GroupMember] = Field([], alias="writers")
|
||||||
@ -237,10 +237,10 @@ class GroupSchema(Schema):
|
|||||||
def resolve_members(obj: Group):
|
def resolve_members(obj: Group):
|
||||||
res = []
|
res = []
|
||||||
for member in obj.user_member.all():
|
for member in obj.user_member.all():
|
||||||
res.append(GroupMember(id=member.url, identifier="usermember", name=member.username))
|
res.append(GroupMember(id=member.url, identifier="usermember", name=member.get_name()))
|
||||||
|
|
||||||
for member in obj.group_member.all():
|
for member in obj.group_member.all():
|
||||||
res.append(GroupMember(id=member.url, identifier="groupmember", name=member.name))
|
res.append(GroupMember(id=member.url, identifier="groupmember", name=member.get_name()))
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -374,7 +374,7 @@ class PackageSchema(Schema):
|
|||||||
).values_list("user", flat=True)
|
).values_list("user", flat=True)
|
||||||
).distinct()
|
).distinct()
|
||||||
|
|
||||||
return [{u.id: u.name} for u in users]
|
return [{u.id: u.get_name()} for u in users]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_writers(obj: Package):
|
def resolve_writers(obj: Package):
|
||||||
@ -384,7 +384,7 @@ class PackageSchema(Schema):
|
|||||||
).values_list("user", flat=True)
|
).values_list("user", flat=True)
|
||||||
).distinct()
|
).distinct()
|
||||||
|
|
||||||
return [{u.id: u.name} for u in users]
|
return [{u.id: u.get_name()} for u in users]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_review_comment(obj):
|
def resolve_review_comment(obj):
|
||||||
@ -966,7 +966,12 @@ def create_package_simple_rule(
|
|||||||
raise ValueError("Not yet implemented!")
|
raise ValueError("Not yet implemented!")
|
||||||
else:
|
else:
|
||||||
sr = SimpleAmbitRule.create(
|
sr = SimpleAmbitRule.create(
|
||||||
p, r.name, r.description, r.smirks, r.reactantFilterSmarts, r.productFilterSmarts
|
p,
|
||||||
|
r.name,
|
||||||
|
r.description,
|
||||||
|
r.smirks,
|
||||||
|
r.reactantFilterSmarts,
|
||||||
|
r.productFilterSmarts,
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(sr.url)
|
return redirect(sr.url)
|
||||||
@ -1119,7 +1124,7 @@ class ReactionSchema(Schema):
|
|||||||
name: str = Field(None, alias="name")
|
name: str = Field(None, alias="name")
|
||||||
pathways: List["SimplePathway"] = Field([], alias="related_pathways")
|
pathways: List["SimplePathway"] = Field([], alias="related_pathways")
|
||||||
products: List["ReactionCompoundStructure"] = Field([], alias="products")
|
products: List["ReactionCompoundStructure"] = Field([], alias="products")
|
||||||
references: List[Dict[str, List[str]]] = Field([], alias="references")
|
references: Dict[str, List[str]] = Field({}, alias="references")
|
||||||
reviewStatus: str = Field(None, alias="review_status")
|
reviewStatus: str = Field(None, alias="review_status")
|
||||||
scenarios: List["SimpleScenario"] = Field([], alias="scenarios")
|
scenarios: List["SimpleScenario"] = Field([], alias="scenarios")
|
||||||
smirks: str = Field("", alias="smirks")
|
smirks: str = Field("", alias="smirks")
|
||||||
@ -1135,8 +1140,12 @@ class ReactionSchema(Schema):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_references(obj: Reaction):
|
def resolve_references(obj: Reaction):
|
||||||
# TODO
|
rhea_refs = []
|
||||||
return []
|
for rhea in obj.get_rhea_identifiers():
|
||||||
|
rhea_refs.append(f"{rhea.identifier_value}")
|
||||||
|
|
||||||
|
# TODO UniProt
|
||||||
|
return {"rheaReferences": rhea_refs, "uniprotCount": []}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_medline_references(obj: Reaction):
|
def resolve_medline_references(obj: Reaction):
|
||||||
@ -1715,7 +1724,7 @@ class EdgeSchema(Schema):
|
|||||||
id: str = Field(None, alias="url")
|
id: str = Field(None, alias="url")
|
||||||
identifier: str = "edge"
|
identifier: str = "edge"
|
||||||
name: str = Field(None, alias="name")
|
name: str = Field(None, alias="name")
|
||||||
reactionName: str = Field(None, alias="edge_label.name")
|
reactionName: str = Field(None, alias="edge_label.get_name")
|
||||||
reactionURI: str = Field(None, alias="edge_label.url")
|
reactionURI: str = Field(None, alias="edge_label.url")
|
||||||
reviewStatus: str = Field(None, alias="review_status")
|
reviewStatus: str = Field(None, alias="review_status")
|
||||||
scenarios: List["SimpleScenario"] = Field([], alias="scenarios")
|
scenarios: List["SimpleScenario"] = Field([], alias="scenarios")
|
||||||
@ -1764,7 +1773,7 @@ class CreateEdge(Schema):
|
|||||||
|
|
||||||
|
|
||||||
@router.post(
|
@router.post(
|
||||||
"/package/{uuid:package_uuid}/üathway/{uuid:pathway_uuid}/edge",
|
"/package/{uuid:package_uuid}/pathway/{uuid:pathway_uuid}/edge",
|
||||||
response={200: str | Any, 403: Error},
|
response={200: str | Any, 403: Error},
|
||||||
)
|
)
|
||||||
def add_pathway_edge(request, package_uuid, pathway_uuid, e: Form[CreateEdge]):
|
def add_pathway_edge(request, package_uuid, pathway_uuid, e: Form[CreateEdge]):
|
||||||
@ -1783,10 +1792,26 @@ def add_pathway_edge(request, package_uuid, pathway_uuid, e: Form[CreateEdge]):
|
|||||||
|
|
||||||
if e.edgeAsSmirks:
|
if e.edgeAsSmirks:
|
||||||
for ed in e.edgeAsSmirks.split(">>")[0].split("\\."):
|
for ed in e.edgeAsSmirks.split(">>")[0].split("\\."):
|
||||||
educts.append(Node.objects.get(pathway=pw, default_node_label__smiles=ed))
|
stand_ed = FormatConverter.standardize(ed, remove_stereo=True)
|
||||||
|
educts.append(
|
||||||
|
Node.objects.get(
|
||||||
|
pathway=pw,
|
||||||
|
default_node_label=CompoundStructure.objects.get(
|
||||||
|
compound__package=p, smiles=stand_ed
|
||||||
|
).compound.default_structure,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
for pr in e.edgeAsSmirks.split(">>")[1].split("\\."):
|
for pr in e.edgeAsSmirks.split(">>")[1].split("\\."):
|
||||||
products.append(Node.objects.get(pathway=pw, default_node_label__smiles=pr))
|
stand_pr = FormatConverter.standardize(pr, remove_stereo=True)
|
||||||
|
products.append(
|
||||||
|
Node.objects.get(
|
||||||
|
pathway=pw,
|
||||||
|
default_node_label=CompoundStructure.objects.get(
|
||||||
|
compound__package=p, smiles=stand_pr
|
||||||
|
).compound.default_structure,
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
for ed in e.educts.split(","):
|
for ed in e.educts.split(","):
|
||||||
educts.append(Node.objects.get(pathway=pw, url=ed.strip()))
|
educts.append(Node.objects.get(pathway=pw, url=ed.strip()))
|
||||||
@ -1799,7 +1824,7 @@ def add_pathway_edge(request, package_uuid, pathway_uuid, e: Form[CreateEdge]):
|
|||||||
start_nodes=educts,
|
start_nodes=educts,
|
||||||
end_nodes=products,
|
end_nodes=products,
|
||||||
rule=None,
|
rule=None,
|
||||||
name=e.name,
|
name=None,
|
||||||
description=e.edgeReason,
|
description=e.edgeReason,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1936,7 +1961,7 @@ def get_model(request, package_uuid, model_uuid, c: Query[Classify]):
|
|||||||
if pr.rule:
|
if pr.rule:
|
||||||
res["id"] = pr.rule.url
|
res["id"] = pr.rule.url
|
||||||
res["identifier"] = pr.rule.get_rule_identifier()
|
res["identifier"] = pr.rule.get_rule_identifier()
|
||||||
res["name"] = pr.rule.name
|
res["name"] = pr.rule.get_name()
|
||||||
res["reviewStatus"] = (
|
res["reviewStatus"] = (
|
||||||
"reviewed" if pr.rule.package.reviewed else "unreviewed"
|
"reviewed" if pr.rule.package.reviewed else "unreviewed"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -8,7 +8,6 @@ from epdb.logic import UserManager, GroupManager, PackageManager, SettingManager
|
|||||||
from epdb.models import (
|
from epdb.models import (
|
||||||
UserSettingPermission,
|
UserSettingPermission,
|
||||||
MLRelativeReasoning,
|
MLRelativeReasoning,
|
||||||
EnviFormer,
|
|
||||||
Permission,
|
Permission,
|
||||||
User,
|
User,
|
||||||
ExternalDatabase,
|
ExternalDatabase,
|
||||||
@ -231,7 +230,6 @@ class Command(BaseCommand):
|
|||||||
package=pack,
|
package=pack,
|
||||||
rule_packages=[mapping["EAWAG-BBD"]],
|
rule_packages=[mapping["EAWAG-BBD"]],
|
||||||
data_packages=[mapping["EAWAG-BBD"]],
|
data_packages=[mapping["EAWAG-BBD"]],
|
||||||
eval_packages=[],
|
|
||||||
threshold=0.5,
|
threshold=0.5,
|
||||||
name="ECC - BBD - T0.5",
|
name="ECC - BBD - T0.5",
|
||||||
description="ML Relative Reasoning",
|
description="ML Relative Reasoning",
|
||||||
@ -239,7 +237,3 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
ml_model.build_dataset()
|
ml_model.build_dataset()
|
||||||
ml_model.build_model()
|
ml_model.build_model()
|
||||||
|
|
||||||
# If available, create EnviFormerModel
|
|
||||||
if s.ENVIFORMER_PRESENT:
|
|
||||||
EnviFormer.create(pack, "EnviFormer - T0.5", "EnviFormer Model with Threshold 0.5", 0.5)
|
|
||||||
|
|||||||
@ -47,7 +47,7 @@ class Command(BaseCommand):
|
|||||||
"description": model.description,
|
"description": model.description,
|
||||||
"kv": model.kv,
|
"kv": model.kv,
|
||||||
"data_packages_uuids": [str(p.uuid) for p in model.data_packages.all()],
|
"data_packages_uuids": [str(p.uuid) for p in model.data_packages.all()],
|
||||||
"eval_packages_uuids": [str(p.uuid) for p in model.data_packages.all()],
|
"eval_packages_uuids": [str(p.uuid) for p in model.eval_packages.all()],
|
||||||
"threshold": model.threshold,
|
"threshold": model.threshold,
|
||||||
"eval_results": model.eval_results,
|
"eval_results": model.eval_results,
|
||||||
"multigen_eval": model.multigen_eval,
|
"multigen_eval": model.multigen_eval,
|
||||||
|
|||||||
144
epdb/models.py
144
epdb/models.py
@ -77,6 +77,9 @@ class User(AbstractUser):
|
|||||||
USERNAME_FIELD = "email"
|
USERNAME_FIELD = "email"
|
||||||
REQUIRED_FIELDS = ["username"]
|
REQUIRED_FIELDS = ["username"]
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return self.username
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.url:
|
if not self.url:
|
||||||
self.url = self._url()
|
self.url = self._url()
|
||||||
@ -208,7 +211,10 @@ class Group(TimeStampedModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.name} (pk={self.pk})"
|
return f"{self.get_name()} (pk={self.pk})"
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.url:
|
if not self.url:
|
||||||
@ -596,7 +602,7 @@ class EnviPathModel(TimeStampedModel):
|
|||||||
res = {
|
res = {
|
||||||
"url": self.url,
|
"url": self.url,
|
||||||
"uuid": str(self.uuid),
|
"uuid": str(self.uuid),
|
||||||
"name": self.name,
|
"name": self.get_name(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if include_description:
|
if include_description:
|
||||||
@ -609,11 +615,14 @@ class EnviPathModel(TimeStampedModel):
|
|||||||
return self.kv.get(k, default)
|
return self.kv.get(k, default)
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.name} (pk={self.pk})"
|
return f"{self.get_name()} (pk={self.pk})"
|
||||||
|
|
||||||
|
|
||||||
class AliasMixin(models.Model):
|
class AliasMixin(models.Model):
|
||||||
@ -624,7 +633,7 @@ class AliasMixin(models.Model):
|
|||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def add_alias(self, new_alias, set_as_default=False):
|
def add_alias(self, new_alias, set_as_default=False):
|
||||||
if set_as_default:
|
if set_as_default:
|
||||||
self.aliases.append(self.name)
|
self.aliases.append(self.get_name())
|
||||||
self.name = new_alias
|
self.name = new_alias
|
||||||
|
|
||||||
if new_alias in self.aliases:
|
if new_alias in self.aliases:
|
||||||
@ -765,15 +774,17 @@ class Compound(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdentifierMixin
|
|||||||
logger.debug(
|
logger.debug(
|
||||||
f"#Structures: {num_structs} - #Standardized SMILES: {len(stand_smiles)}"
|
f"#Structures: {num_structs} - #Standardized SMILES: {len(stand_smiles)}"
|
||||||
)
|
)
|
||||||
logger.debug(f"Couldn't infer normalized structure for {self.name} - {self.url}")
|
logger.debug(
|
||||||
|
f"Couldn't infer normalized structure for {self.get_name()} - {self.url}"
|
||||||
|
)
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Couldn't find nor infer normalized structure for {self.name} ({self.url})"
|
f"Couldn't find nor infer normalized structure for {self.get_name()} ({self.url})"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
cs = CompoundStructure.create(
|
cs = CompoundStructure.create(
|
||||||
self,
|
self,
|
||||||
stand_smiles.pop(),
|
stand_smiles.pop(),
|
||||||
name="Normalized structure of {}".format(self.name),
|
name="Normalized structure of {}".format(self.get_name()),
|
||||||
description="{} (in its normalized form)".format(self.description),
|
description="{} (in its normalized form)".format(self.description),
|
||||||
normalized_structure=True,
|
normalized_structure=True,
|
||||||
)
|
)
|
||||||
@ -848,8 +859,10 @@ class Compound(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdentifierMixin
|
|||||||
if name is not None:
|
if name is not None:
|
||||||
# Clean for potential XSS
|
# Clean for potential XSS
|
||||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||||
|
|
||||||
if name is None or name == "":
|
if name is None or name == "":
|
||||||
name = f"Compound {Compound.objects.filter(package=package).count() + 1}"
|
name = f"Compound {Compound.objects.filter(package=package).count() + 1}"
|
||||||
|
|
||||||
c.name = name
|
c.name = name
|
||||||
|
|
||||||
# We have a default here only set the value if it carries some payload
|
# We have a default here only set the value if it carries some payload
|
||||||
@ -978,7 +991,7 @@ class Compound(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdentifierMixin
|
|||||||
cs = CompoundStructure.create(
|
cs = CompoundStructure.create(
|
||||||
existing_normalized_compound,
|
existing_normalized_compound,
|
||||||
structure.smiles,
|
structure.smiles,
|
||||||
name=structure.name,
|
name=structure.get_name(),
|
||||||
description=structure.description,
|
description=structure.description,
|
||||||
normalized_structure=structure.normalized_structure,
|
normalized_structure=structure.normalized_structure,
|
||||||
)
|
)
|
||||||
@ -989,13 +1002,13 @@ class Compound(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdentifierMixin
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Found a CompoundStructure for {default_structure_smiles} but not for {normalized_structure_smiles} in target package {target.name}"
|
f"Found a CompoundStructure for {default_structure_smiles} but not for {normalized_structure_smiles} in target package {target.get_name()}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Here we can safely use Compound.objects.create as we won't end up in a duplicate
|
# Here we can safely use Compound.objects.create as we won't end up in a duplicate
|
||||||
new_compound = Compound.objects.create(
|
new_compound = Compound.objects.create(
|
||||||
package=target,
|
package=target,
|
||||||
name=self.name,
|
name=self.get_name(),
|
||||||
description=self.description,
|
description=self.description,
|
||||||
kv=self.kv.copy() if self.kv else {},
|
kv=self.kv.copy() if self.kv else {},
|
||||||
)
|
)
|
||||||
@ -1011,7 +1024,7 @@ class Compound(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdentifierMixin
|
|||||||
canonical_smiles=structure.canonical_smiles,
|
canonical_smiles=structure.canonical_smiles,
|
||||||
inchikey=structure.inchikey,
|
inchikey=structure.inchikey,
|
||||||
normalized_structure=structure.normalized_structure,
|
normalized_structure=structure.normalized_structure,
|
||||||
name=structure.name,
|
name=structure.get_name(),
|
||||||
description=structure.description,
|
description=structure.description,
|
||||||
kv=structure.kv.copy() if structure.kv else {},
|
kv=structure.kv.copy() if structure.kv else {},
|
||||||
)
|
)
|
||||||
@ -1050,11 +1063,8 @@ class Compound(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdentifierMixin
|
|||||||
def half_lifes(self):
|
def half_lifes(self):
|
||||||
hls: Dict[Scenario, List[HalfLife]] = defaultdict(list)
|
hls: Dict[Scenario, List[HalfLife]] = defaultdict(list)
|
||||||
|
|
||||||
for n in self.related_nodes:
|
for cs in self.structures:
|
||||||
for scen in n.scenarios.all().order_by("name"):
|
hls.update(cs.half_lifes())
|
||||||
for ai in scen.get_additional_information():
|
|
||||||
if isinstance(ai, HalfLife):
|
|
||||||
hls[scen].append(ai)
|
|
||||||
|
|
||||||
return dict(hls)
|
return dict(hls)
|
||||||
|
|
||||||
@ -1104,6 +1114,7 @@ class CompoundStructure(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdenti
|
|||||||
# Clean for potential XSS
|
# Clean for potential XSS
|
||||||
if name is not None:
|
if name is not None:
|
||||||
cs.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
cs.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||||
|
|
||||||
if description is not None:
|
if description is not None:
|
||||||
cs.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
cs.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||||
|
|
||||||
@ -1147,6 +1158,21 @@ class CompoundStructure(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdenti
|
|||||||
def is_default_structure(self):
|
def is_default_structure(self):
|
||||||
return self.compound.default_structure == self
|
return self.compound.default_structure == self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def related_nodes(self):
|
||||||
|
return Node.objects.filter(node_labels__in=[self], pathway__package=self.compound.package)
|
||||||
|
|
||||||
|
def half_lifes(self):
|
||||||
|
hls: Dict[Scenario, List[HalfLife]] = defaultdict(list)
|
||||||
|
|
||||||
|
for n in self.related_nodes:
|
||||||
|
for scen in n.scenarios.all().order_by("name"):
|
||||||
|
for ai in scen.get_additional_information():
|
||||||
|
if isinstance(ai, HalfLife):
|
||||||
|
hls[scen].append(ai)
|
||||||
|
|
||||||
|
return dict(hls)
|
||||||
|
|
||||||
|
|
||||||
class EnzymeLink(EnviPathModel, KEGGIdentifierMixin):
|
class EnzymeLink(EnviPathModel, KEGGIdentifierMixin):
|
||||||
rule = models.ForeignKey("Rule", on_delete=models.CASCADE, db_index=True)
|
rule = models.ForeignKey("Rule", on_delete=models.CASCADE, db_index=True)
|
||||||
@ -1218,7 +1244,7 @@ class Rule(PolymorphicModel, EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
if rule_type == SimpleAmbitRule:
|
if rule_type == SimpleAmbitRule:
|
||||||
new_rule = SimpleAmbitRule.create(
|
new_rule = SimpleAmbitRule.create(
|
||||||
package=target,
|
package=target,
|
||||||
name=self.name,
|
name=self.get_name(),
|
||||||
description=self.description,
|
description=self.description,
|
||||||
smirks=self.smirks,
|
smirks=self.smirks,
|
||||||
reactant_filter_smarts=self.reactant_filter_smarts,
|
reactant_filter_smarts=self.reactant_filter_smarts,
|
||||||
@ -1232,7 +1258,7 @@ class Rule(PolymorphicModel, EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
elif rule_type == SimpleRDKitRule:
|
elif rule_type == SimpleRDKitRule:
|
||||||
new_rule = SimpleRDKitRule.create(
|
new_rule = SimpleRDKitRule.create(
|
||||||
package=target,
|
package=target,
|
||||||
name=self.name,
|
name=self.get_name(),
|
||||||
description=self.description,
|
description=self.description,
|
||||||
reaction_smarts=self.reaction_smarts,
|
reaction_smarts=self.reaction_smarts,
|
||||||
)
|
)
|
||||||
@ -1250,7 +1276,7 @@ class Rule(PolymorphicModel, EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
new_rule = ParallelRule.create(
|
new_rule = ParallelRule.create(
|
||||||
package=target,
|
package=target,
|
||||||
simple_rules=new_srs,
|
simple_rules=new_srs,
|
||||||
name=self.name,
|
name=self.get_name(),
|
||||||
description=self.description,
|
description=self.description,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1624,9 +1650,11 @@ class Reaction(EnviPathModel, AliasMixin, ScenarioMixin, ReactionIdentifierMixin
|
|||||||
|
|
||||||
r = Reaction()
|
r = Reaction()
|
||||||
r.package = package
|
r.package = package
|
||||||
|
|
||||||
# Clean for potential XSS
|
# Clean for potential XSS
|
||||||
if name is not None and name.strip() != "":
|
if name is not None and name.strip() != "":
|
||||||
r.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).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 name.strip() != "":
|
||||||
r.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
r.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||||
|
|
||||||
@ -1674,7 +1702,7 @@ class Reaction(EnviPathModel, AliasMixin, ScenarioMixin, ReactionIdentifierMixin
|
|||||||
|
|
||||||
new_reaction = Reaction.create(
|
new_reaction = Reaction.create(
|
||||||
package=target,
|
package=target,
|
||||||
name=self.name,
|
name=self.get_name(),
|
||||||
description=self.description,
|
description=self.description,
|
||||||
educts=copied_reaction_educts,
|
educts=copied_reaction_educts,
|
||||||
products=copied_reaction_products,
|
products=copied_reaction_products,
|
||||||
@ -1830,7 +1858,9 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
|
|
||||||
# We shouldn't lose or make up nodes...
|
# We shouldn't lose or make up nodes...
|
||||||
if len(nodes) != len(self.nodes):
|
if len(nodes) != len(self.nodes):
|
||||||
logger.debug(f"{self.name}: Num Nodes {len(nodes)} vs. DB Nodes {len(self.nodes)}")
|
logger.debug(
|
||||||
|
f"{self.get_name()}: Num Nodes {len(nodes)} vs. DB Nodes {len(self.nodes)}"
|
||||||
|
)
|
||||||
|
|
||||||
links = [e.d3_json() for e in self.edges]
|
links = [e.d3_json() for e in self.edges]
|
||||||
|
|
||||||
@ -1898,7 +1928,7 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
"isIncremental": self.kv.get("mode") == "incremental",
|
"isIncremental": self.kv.get("mode") == "incremental",
|
||||||
"isPredicted": self.kv.get("mode") == "predicted",
|
"isPredicted": self.kv.get("mode") == "predicted",
|
||||||
"lastModified": self.modified.strftime("%Y-%m-%d %H:%M:%S"),
|
"lastModified": self.modified.strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
"pathwayName": self.name,
|
"pathwayName": self.get_name(),
|
||||||
"reviewStatus": "reviewed" if self.package.reviewed else "unreviewed",
|
"reviewStatus": "reviewed" if self.package.reviewed else "unreviewed",
|
||||||
"scenarios": [],
|
"scenarios": [],
|
||||||
"upToDate": True,
|
"upToDate": True,
|
||||||
@ -1941,14 +1971,14 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
if include_pathway_url:
|
if include_pathway_url:
|
||||||
row.append(n.pathway.url)
|
row.append(n.pathway.url)
|
||||||
|
|
||||||
row += [cs.smiles, cs.name, n.depth]
|
row += [cs.smiles, cs.get_name(), n.depth]
|
||||||
|
|
||||||
edges = self.edges.filter(end_nodes__in=[n])
|
edges = self.edges.filter(end_nodes__in=[n])
|
||||||
if len(edges):
|
if len(edges):
|
||||||
for e in edges:
|
for e in edges:
|
||||||
_row = row.copy()
|
_row = row.copy()
|
||||||
_row.append(e.kv.get("probability"))
|
_row.append(e.kv.get("probability"))
|
||||||
_row.append(",".join([r.name for r in e.edge_label.rules.all()]))
|
_row.append(",".join([r.get_name() for r in e.edge_label.rules.all()]))
|
||||||
_row.append(",".join([r.url for r in e.edge_label.rules.all()]))
|
_row.append(",".join([r.url for r in e.edge_label.rules.all()]))
|
||||||
_row.append(e.start_nodes.all()[0].default_node_label.smiles)
|
_row.append(e.start_nodes.all()[0].default_node_label.smiles)
|
||||||
rows.append(_row)
|
rows.append(_row)
|
||||||
@ -1979,12 +2009,14 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
if name is not None:
|
if name is not None:
|
||||||
# Clean for potential XSS
|
# Clean for potential XSS
|
||||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||||
|
|
||||||
if name is None or name == "":
|
if name is None or name == "":
|
||||||
name = f"Pathway {Pathway.objects.filter(package=package).count() + 1}"
|
name = f"Pathway {Pathway.objects.filter(package=package).count() + 1}"
|
||||||
|
|
||||||
pw.name = name
|
pw.name = name
|
||||||
if description is not None and description.strip() != "":
|
if description is not None and description.strip() != "":
|
||||||
pw.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
pw.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||||
|
|
||||||
pw.predicted = predicted
|
pw.predicted = predicted
|
||||||
|
|
||||||
pw.save()
|
pw.save()
|
||||||
@ -2009,7 +2041,7 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
# deduplicated
|
# deduplicated
|
||||||
new_pathway = Pathway.objects.create(
|
new_pathway = Pathway.objects.create(
|
||||||
package=target,
|
package=target,
|
||||||
name=self.name,
|
name=self.get_name(),
|
||||||
description=self.description,
|
description=self.description,
|
||||||
setting=self.setting, # TODO copy settings?
|
setting=self.setting, # TODO copy settings?
|
||||||
kv=self.kv.copy() if self.kv else {},
|
kv=self.kv.copy() if self.kv else {},
|
||||||
@ -2039,7 +2071,7 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
pathway=new_pathway,
|
pathway=new_pathway,
|
||||||
default_node_label=copied_structure,
|
default_node_label=copied_structure,
|
||||||
depth=node.depth,
|
depth=node.depth,
|
||||||
name=node.name,
|
name=node.get_name(),
|
||||||
description=node.description,
|
description=node.description,
|
||||||
kv=node.kv.copy() if node.kv else {},
|
kv=node.kv.copy() if node.kv else {},
|
||||||
)
|
)
|
||||||
@ -2063,7 +2095,7 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
new_edge = Edge.objects.create(
|
new_edge = Edge.objects.create(
|
||||||
pathway=new_pathway,
|
pathway=new_pathway,
|
||||||
edge_label=copied_reaction,
|
edge_label=copied_reaction,
|
||||||
name=edge.name,
|
name=edge.get_name(),
|
||||||
description=edge.description,
|
description=edge.description,
|
||||||
kv=edge.kv.copy() if edge.kv else {},
|
kv=edge.kv.copy() if edge.kv else {},
|
||||||
)
|
)
|
||||||
@ -2123,6 +2155,18 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
def _url(self):
|
def _url(self):
|
||||||
return "{}/node/{}".format(self.pathway.url, self.uuid)
|
return "{}/node/{}".format(self.pathway.url, self.uuid)
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
non_generic_name = True
|
||||||
|
|
||||||
|
if self.name == "no name":
|
||||||
|
non_generic_name = False
|
||||||
|
|
||||||
|
return (
|
||||||
|
self.name
|
||||||
|
if non_generic_name
|
||||||
|
else f"{self.default_node_label.name} (taken from underlying structure)"
|
||||||
|
)
|
||||||
|
|
||||||
def d3_json(self):
|
def d3_json(self):
|
||||||
app_domain_data = self.get_app_domain_assessment_data()
|
app_domain_data = self.get_app_domain_assessment_data()
|
||||||
|
|
||||||
@ -2135,9 +2179,9 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
"image_svg": IndigoUtils.mol_to_svg(
|
"image_svg": IndigoUtils.mol_to_svg(
|
||||||
self.default_node_label.smiles, width=40, height=40
|
self.default_node_label.smiles, width=40, height=40
|
||||||
),
|
),
|
||||||
"name": self.default_node_label.name,
|
"name": self.get_name(),
|
||||||
"smiles": self.default_node_label.smiles,
|
"smiles": self.default_node_label.smiles,
|
||||||
"scenarios": [{"name": s.name, "url": s.url} for s in self.scenarios.all()],
|
"scenarios": [{"name": s.get_name(), "url": s.url} for s in self.scenarios.all()],
|
||||||
"app_domain": {
|
"app_domain": {
|
||||||
"inside_app_domain": app_domain_data["assessment"]["inside_app_domain"]
|
"inside_app_domain": app_domain_data["assessment"]["inside_app_domain"]
|
||||||
if app_domain_data
|
if app_domain_data
|
||||||
@ -2205,7 +2249,7 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
res = super().simple_json()
|
res = super().simple_json()
|
||||||
name = res.get("name", None)
|
name = res.get("name", None)
|
||||||
if name == "no name":
|
if name == "no name":
|
||||||
res["name"] = self.default_node_label.name
|
res["name"] = self.default_node_label.get_name()
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -2229,18 +2273,24 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
|
|
||||||
def d3_json(self):
|
def d3_json(self):
|
||||||
edge_json = {
|
edge_json = {
|
||||||
"name": self.name,
|
"name": self.get_name(),
|
||||||
"id": self.url,
|
"id": self.url,
|
||||||
"url": self.url,
|
"url": self.url,
|
||||||
"image": self.url + "?image=svg",
|
"image": self.url + "?image=svg",
|
||||||
"reaction": {"name": self.edge_label.name, "url": self.edge_label.url}
|
"reaction": {
|
||||||
|
"name": self.edge_label.get_name(),
|
||||||
|
"url": self.edge_label.url,
|
||||||
|
"rules": [
|
||||||
|
{"name": r.get_name(), "url": r.url} for r in self.edge_label.rules.all()
|
||||||
|
],
|
||||||
|
}
|
||||||
if self.edge_label
|
if self.edge_label
|
||||||
else None,
|
else None,
|
||||||
"multi_step": self.edge_label.multi_step if self.edge_label else False,
|
"multi_step": self.edge_label.multi_step if self.edge_label else False,
|
||||||
"reaction_probability": self.kv.get("probability"),
|
"reaction_probability": self.kv.get("probability"),
|
||||||
"start_node_urls": [x.url for x in self.start_nodes.all()],
|
"start_node_urls": [x.url for x in self.start_nodes.all()],
|
||||||
"end_node_urls": [x.url for x in self.end_nodes.all()],
|
"end_node_urls": [x.url for x in self.end_nodes.all()],
|
||||||
"scenarios": [{"name": s.name, "url": s.url} for s in self.scenarios.all()],
|
"scenarios": [{"name": s.get_name(), "url": s.url} for s in self.scenarios.all()],
|
||||||
}
|
}
|
||||||
|
|
||||||
for n in self.start_nodes.all():
|
for n in self.start_nodes.all():
|
||||||
@ -2329,10 +2379,22 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
res = super().simple_json()
|
res = super().simple_json()
|
||||||
name = res.get("name", None)
|
name = res.get("name", None)
|
||||||
if name == "no name":
|
if name == "no name":
|
||||||
res["name"] = self.edge_label.name
|
res["name"] = self.edge_label.get_name()
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
non_generic_name = True
|
||||||
|
|
||||||
|
if self.name == "no name":
|
||||||
|
non_generic_name = False
|
||||||
|
|
||||||
|
return (
|
||||||
|
self.name
|
||||||
|
if non_generic_name
|
||||||
|
else f"{self.edge_label.name} (taken from underlying reaction)"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EPModel(PolymorphicModel, EnviPathModel):
|
class EPModel(PolymorphicModel, EnviPathModel):
|
||||||
package = models.ForeignKey(
|
package = models.ForeignKey(
|
||||||
@ -2613,7 +2675,7 @@ class PackageBasedModel(EPModel):
|
|||||||
root_compounds.append(pw.root_nodes[0].default_node_label)
|
root_compounds.append(pw.root_nodes[0].default_node_label)
|
||||||
else:
|
else:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Skipping MG Eval of Pathway {pw.name} ({pw.uuid}) as it has no root compounds!"
|
f"Skipping MG Eval of Pathway {pw.get_name()} ({pw.uuid}) as it has no root compounds!"
|
||||||
)
|
)
|
||||||
|
|
||||||
# As we need a Model Instance in our setting, get a fresh copy from db, overwrite the serialized mode and
|
# As we need a Model Instance in our setting, get a fresh copy from db, overwrite the serialized mode and
|
||||||
@ -2739,7 +2801,7 @@ class PackageBasedModel(EPModel):
|
|||||||
pathways.append(pathway)
|
pathways.append(pathway)
|
||||||
else:
|
else:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
f"No root compound in pathway {pathway.name}, excluding from multigen evaluation"
|
f"No root compound in pathway {pathway.get_name()}, excluding from multigen evaluation"
|
||||||
)
|
)
|
||||||
|
|
||||||
# build lookup reaction -> {uuid1, uuid2} for overlap check
|
# build lookup reaction -> {uuid1, uuid2} for overlap check
|
||||||
@ -3071,7 +3133,7 @@ class ApplicabilityDomain(EnviPathModel):
|
|||||||
ad = ApplicabilityDomain()
|
ad = ApplicabilityDomain()
|
||||||
ad.model = mlrr
|
ad.model = mlrr
|
||||||
# ad.uuid = mlrr.uuid
|
# ad.uuid = mlrr.uuid
|
||||||
ad.name = f"AD for {mlrr.name}"
|
ad.name = f"AD for {mlrr.get_name()}"
|
||||||
ad.num_neighbours = num_neighbours
|
ad.num_neighbours = num_neighbours
|
||||||
ad.reliability_threshold = reliability_threshold
|
ad.reliability_threshold = reliability_threshold
|
||||||
ad.local_compatibilty_threshold = local_compatibility_threshold
|
ad.local_compatibilty_threshold = local_compatibility_threshold
|
||||||
@ -3355,7 +3417,7 @@ class EnviFormer(PackageBasedModel):
|
|||||||
)
|
)
|
||||||
for smiles in smiles_list
|
for smiles in smiles_list
|
||||||
]
|
]
|
||||||
logger.info(f"Submitting {canon_smiles} to {self.name}")
|
logger.info(f"Submitting {canon_smiles} to {self.get_name()}")
|
||||||
start = datetime.now()
|
start = datetime.now()
|
||||||
products_list = self.model.predict_batch(canon_smiles)
|
products_list = self.model.predict_batch(canon_smiles)
|
||||||
end = datetime.now()
|
end = datetime.now()
|
||||||
@ -3512,7 +3574,7 @@ class EnviFormer(PackageBasedModel):
|
|||||||
root_node = p.root_nodes
|
root_node = p.root_nodes
|
||||||
if len(root_node) > 1:
|
if len(root_node) > 1:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
f"Pathway {p.name} has more than one root compound, only {root_node[0]} will be used"
|
f"Pathway {p.get_name()} has more than one root compound, only {root_node[0]} will be used"
|
||||||
)
|
)
|
||||||
root_node = ".".join(
|
root_node = ".".join(
|
||||||
[
|
[
|
||||||
@ -3632,7 +3694,7 @@ class EnviFormer(PackageBasedModel):
|
|||||||
pathways.append(pathway)
|
pathways.append(pathway)
|
||||||
else:
|
else:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
f"No root compound in pathway {pathway.name}, excluding from multigen evaluation"
|
f"No root compound in pathway {pathway.get_name()}, excluding from multigen evaluation"
|
||||||
)
|
)
|
||||||
|
|
||||||
# build lookup reaction -> {uuid1, uuid2} for overlap check
|
# build lookup reaction -> {uuid1, uuid2} for overlap check
|
||||||
@ -4038,6 +4100,6 @@ class JobLog(TimeStampedModel):
|
|||||||
return self.task_result
|
return self.task_result
|
||||||
|
|
||||||
def is_result_downloadable(self):
|
def is_result_downloadable(self):
|
||||||
downloadable = ["batch_predict"]
|
downloadable = ["batch_predict", "identify_missing_rules"]
|
||||||
|
|
||||||
return self.job_name in downloadable
|
return self.job_name in downloadable
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from uuid import uuid4
|
|||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from celery.utils.functional import LRUCache
|
from celery.utils.functional import LRUCache
|
||||||
from django.conf import settings as s
|
from django.conf import settings as s
|
||||||
|
from django.core.mail import EmailMultiAlternatives
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from epdb.logic import SPathway
|
from epdb.logic import SPathway
|
||||||
@ -73,7 +74,31 @@ def predict_simple(model_pk: int, smiles: str):
|
|||||||
|
|
||||||
@shared_task(queue="background")
|
@shared_task(queue="background")
|
||||||
def send_registration_mail(user_pk: int):
|
def send_registration_mail(user_pk: int):
|
||||||
pass
|
u = User.objects.get(id=user_pk)
|
||||||
|
|
||||||
|
tpl = """Welcome {username}!,
|
||||||
|
|
||||||
|
Thank you for your interest in enviPath.
|
||||||
|
|
||||||
|
The public system is intended for non-commercial use only.
|
||||||
|
We will review your account details and usually activate your account within 24 hours.
|
||||||
|
Once activated, you will be notified by email.
|
||||||
|
|
||||||
|
If we have any questions, we will contact you at this email address.
|
||||||
|
|
||||||
|
Best regards,
|
||||||
|
|
||||||
|
enviPath team"""
|
||||||
|
|
||||||
|
msg = EmailMultiAlternatives(
|
||||||
|
"Your enviPath account",
|
||||||
|
tpl.format(username=u.username),
|
||||||
|
"admin@envipath.org",
|
||||||
|
[u.email],
|
||||||
|
bcc=["admin@envipath.org"],
|
||||||
|
)
|
||||||
|
|
||||||
|
msg.send(fail_silently=False)
|
||||||
|
|
||||||
|
|
||||||
@shared_task(bind=True, queue="model")
|
@shared_task(bind=True, queue="model")
|
||||||
|
|||||||
142
epdb/views.py
142
epdb/views.py
@ -1,7 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Dict, List
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
import nh3
|
import nh3
|
||||||
from django.conf import settings as s
|
from django.conf import settings as s
|
||||||
@ -13,6 +13,7 @@ from django.urls import reverse
|
|||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from envipy_additional_information import NAME_MAPPING
|
from envipy_additional_information import NAME_MAPPING
|
||||||
from oauth2_provider.decorators import protected_resource
|
from oauth2_provider.decorators import protected_resource
|
||||||
|
from sentry_sdk import capture_exception
|
||||||
|
|
||||||
from utilities.chem import FormatConverter, IndigoUtils
|
from utilities.chem import FormatConverter, IndigoUtils
|
||||||
from utilities.decorators import package_permission_required
|
from utilities.decorators import package_permission_required
|
||||||
@ -34,6 +35,7 @@ from .models import (
|
|||||||
EnviFormer,
|
EnviFormer,
|
||||||
EnzymeLink,
|
EnzymeLink,
|
||||||
EPModel,
|
EPModel,
|
||||||
|
ExpansionSchemeChoice,
|
||||||
ExternalDatabase,
|
ExternalDatabase,
|
||||||
ExternalIdentifier,
|
ExternalIdentifier,
|
||||||
Group,
|
Group,
|
||||||
@ -51,7 +53,6 @@ from .models import (
|
|||||||
SimpleAmbitRule,
|
SimpleAmbitRule,
|
||||||
User,
|
User,
|
||||||
UserPackagePermission,
|
UserPackagePermission,
|
||||||
ExpansionSchemeChoice,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -238,6 +239,15 @@ def register(request):
|
|||||||
try:
|
try:
|
||||||
u = UserManager.create_user(username, email, password)
|
u = UserManager.create_user(username, email, password)
|
||||||
logger.info(f"Created user {u.username} ({u.pk})")
|
logger.info(f"Created user {u.username} ({u.pk})")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .tasks import send_registration_mail
|
||||||
|
|
||||||
|
send_registration_mail.delay(u.pk)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to send registration mail to {u.email}: {e}")
|
||||||
|
capture_exception(e)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
context["message"] = "Registration failed! Couldn't create User Account."
|
context["message"] = "Registration failed! Couldn't create User Account."
|
||||||
return render(request, "static/login.html", context)
|
return render(request, "static/login.html", context)
|
||||||
@ -339,7 +349,7 @@ def breadcrumbs(
|
|||||||
{"Package": s.SERVER_URL + "/package"},
|
{"Package": s.SERVER_URL + "/package"},
|
||||||
]
|
]
|
||||||
if first_level_object is not None:
|
if first_level_object is not None:
|
||||||
bread.append({first_level_object.name: first_level_object.url})
|
bread.append({first_level_object.get_name(): first_level_object.url})
|
||||||
|
|
||||||
if second_level_namespace is not None:
|
if second_level_namespace is not None:
|
||||||
bread.append(
|
bread.append(
|
||||||
@ -350,7 +360,7 @@ def breadcrumbs(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if second_level_object is not None:
|
if second_level_object is not None:
|
||||||
bread.append({second_level_object.name: second_level_object.url})
|
bread.append({second_level_object.get_name(): second_level_object.url})
|
||||||
|
|
||||||
if third_level_namespace is not None:
|
if third_level_namespace is not None:
|
||||||
bread.append(
|
bread.append(
|
||||||
@ -361,7 +371,7 @@ def breadcrumbs(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if third_level_object is not None:
|
if third_level_object is not None:
|
||||||
bread.append({third_level_object.name: third_level_object.url})
|
bread.append({third_level_object.get_name(): third_level_object.url})
|
||||||
|
|
||||||
return bread
|
return bread
|
||||||
|
|
||||||
@ -462,7 +472,7 @@ def package_predict_pathway(request, package_uuid):
|
|||||||
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
|
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - Predict Pathway"
|
context["title"] = f"enviPath - {current_package.get_name()} - Predict Pathway"
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
|
|
||||||
return render(request, "predict_pathway.html", context)
|
return render(request, "predict_pathway.html", context)
|
||||||
@ -475,6 +485,10 @@ def packages(request):
|
|||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = "enviPath - Packages"
|
context["title"] = "enviPath - Packages"
|
||||||
context["meta"]["current_package"] = context["meta"]["user"].default_package
|
context["meta"]["current_package"] = context["meta"]["user"].default_package
|
||||||
|
context["breadcrumbs"] = [
|
||||||
|
{"Home": s.SERVER_URL},
|
||||||
|
{"Package": s.SERVER_URL + "/package"},
|
||||||
|
]
|
||||||
|
|
||||||
# Context for paginated template
|
# Context for paginated template
|
||||||
context["entity_type"] = "package"
|
context["entity_type"] = "package"
|
||||||
@ -529,6 +543,10 @@ def compounds(request):
|
|||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = "enviPath - Compounds"
|
context["title"] = "enviPath - Compounds"
|
||||||
context["meta"]["current_package"] = context["meta"]["user"].default_package
|
context["meta"]["current_package"] = context["meta"]["user"].default_package
|
||||||
|
context["breadcrumbs"] = [
|
||||||
|
{"Home": s.SERVER_URL},
|
||||||
|
{"Compound": s.SERVER_URL + "/compound"},
|
||||||
|
]
|
||||||
|
|
||||||
# Context for paginated template
|
# Context for paginated template
|
||||||
context["entity_type"] = "compound"
|
context["entity_type"] = "compound"
|
||||||
@ -759,7 +777,7 @@ def package_models(request, package_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - Models"
|
context["title"] = f"enviPath - {current_package.get_name()} - Models"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "model"
|
context["object_type"] = "model"
|
||||||
@ -781,7 +799,7 @@ def package_models(request, package_uuid):
|
|||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{
|
{
|
||||||
"objects": [
|
"objects": [
|
||||||
{"name": pw.name, "url": pw.url, "reviewed": current_package.reviewed}
|
{"name": pw.get_name(), "url": pw.url, "reviewed": current_package.reviewed}
|
||||||
for pw in (
|
for pw in (
|
||||||
reviewed_model_qs if current_package.reviewed else unreviewed_model_qs
|
reviewed_model_qs if current_package.reviewed else unreviewed_model_qs
|
||||||
)
|
)
|
||||||
@ -931,7 +949,7 @@ def package_model(request, package_uuid, model_uuid):
|
|||||||
return JsonResponse(app_domain_assessment, safe=False)
|
return JsonResponse(app_domain_assessment, safe=False)
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - {current_model.name}"
|
context["title"] = f"enviPath - {current_package.get_name()} - {current_model.get_name()}"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "model"
|
context["object_type"] = "model"
|
||||||
@ -1009,7 +1027,7 @@ def package(request, package_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
if request.GET.get("export", False) == "true":
|
if request.GET.get("export", False) == "true":
|
||||||
filename = f"{current_package.name.replace(' ', '_')}_{current_package.uuid}.json"
|
filename = f"{current_package.get_name().replace(' ', '_')}_{current_package.uuid}.json"
|
||||||
pack_json = PackageManager.export_package(
|
pack_json = PackageManager.export_package(
|
||||||
current_package, include_models=False, include_external_identifiers=False
|
current_package, include_models=False, include_external_identifiers=False
|
||||||
)
|
)
|
||||||
@ -1019,7 +1037,7 @@ def package(request, package_uuid):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name}"
|
context["title"] = f"enviPath - {current_package.get_name()}"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "package"
|
context["object_type"] = "package"
|
||||||
@ -1056,7 +1074,7 @@ def package(request, package_uuid):
|
|||||||
if current_user.default_package == current_package:
|
if current_user.default_package == current_package:
|
||||||
return error(
|
return error(
|
||||||
request,
|
request,
|
||||||
f'Package "{current_package.name}" is the default and cannot be deleted!',
|
f'Package "{current_package.get_name()}" is the default and cannot be deleted!',
|
||||||
"You cannot delete the default package. If you want to delete this package you have to set another default package first.",
|
"You cannot delete the default package. If you want to delete this package you have to set another default package first.",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1154,7 +1172,7 @@ def package_compounds(request, package_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - Compounds"
|
context["title"] = f"enviPath - {current_package.get_name()} - Compounds"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "compound"
|
context["object_type"] = "compound"
|
||||||
@ -1179,7 +1197,7 @@ def package_compounds(request, package_uuid):
|
|||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{
|
{
|
||||||
"objects": [
|
"objects": [
|
||||||
{"name": pw.name, "url": pw.url, "reviewed": current_package.reviewed}
|
{"name": pw.get_name(), "url": pw.url, "reviewed": current_package.reviewed}
|
||||||
for pw in (
|
for pw in (
|
||||||
reviewed_compound_qs
|
reviewed_compound_qs
|
||||||
if current_package.reviewed
|
if current_package.reviewed
|
||||||
@ -1216,7 +1234,9 @@ def package_compound(request, package_uuid, compound_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - {current_compound.name}"
|
context["title"] = (
|
||||||
|
f"enviPath - {current_package.get_name()} - {current_compound.get_name()}"
|
||||||
|
)
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "compound"
|
context["object_type"] = "compound"
|
||||||
@ -1300,7 +1320,7 @@ def package_compound_structures(request, package_uuid, compound_uuid):
|
|||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = (
|
context["title"] = (
|
||||||
f"enviPath - {current_package.name} - {current_compound.name} - Structures"
|
f"enviPath - {current_package.get_name()} - {current_compound.get_name()} - Structures"
|
||||||
)
|
)
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
@ -1309,7 +1329,7 @@ def package_compound_structures(request, package_uuid, compound_uuid):
|
|||||||
current_package, "compound", current_compound, "structure"
|
current_package, "compound", current_compound, "structure"
|
||||||
)
|
)
|
||||||
context["entity_type"] = "structure"
|
context["entity_type"] = "structure"
|
||||||
context["page_title"] = f"{current_compound.name} - Structures"
|
context["page_title"] = f"{current_compound.get_name()} - Structures"
|
||||||
context["api_endpoint"] = (
|
context["api_endpoint"] = (
|
||||||
f"/api/v1/package/{current_package.uuid}/compound/{current_compound.uuid}/structure/"
|
f"/api/v1/package/{current_package.uuid}/compound/{current_compound.uuid}/structure/"
|
||||||
)
|
)
|
||||||
@ -1362,7 +1382,7 @@ def package_compound_structure(request, package_uuid, compound_uuid, structure_u
|
|||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = (
|
context["title"] = (
|
||||||
f"enviPath - {current_package.name} - {current_compound.name} - {current_structure.name}"
|
f"enviPath - {current_package.get_name()} - {current_compound.get_name()} - {current_structure.get_name()}"
|
||||||
)
|
)
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
@ -1468,7 +1488,7 @@ def package_rules(request, package_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - Rules"
|
context["title"] = f"enviPath - {current_package.get_name()} - Rules"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "rule"
|
context["object_type"] = "rule"
|
||||||
@ -1490,7 +1510,7 @@ def package_rules(request, package_uuid):
|
|||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{
|
{
|
||||||
"objects": [
|
"objects": [
|
||||||
{"name": pw.name, "url": pw.url, "reviewed": current_package.reviewed}
|
{"name": pw.get_name(), "url": pw.url, "reviewed": current_package.reviewed}
|
||||||
for pw in (
|
for pw in (
|
||||||
reviewed_rule_qs if current_package.reviewed else unreviewed_rule_qs
|
reviewed_rule_qs if current_package.reviewed else unreviewed_rule_qs
|
||||||
)
|
)
|
||||||
@ -1580,7 +1600,7 @@ def package_rule(request, package_uuid, rule_uuid):
|
|||||||
content_type="image/svg+xml",
|
content_type="image/svg+xml",
|
||||||
)
|
)
|
||||||
|
|
||||||
context["title"] = f"enviPath - {current_package.name} - {current_rule.name}"
|
context["title"] = f"enviPath - {current_package.get_name()} - {current_rule.get_name()}"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "rule"
|
context["object_type"] = "rule"
|
||||||
@ -1653,7 +1673,7 @@ def package_rule_enzymelink(request, package_uuid, rule_uuid, enzymelink_uuid):
|
|||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
|
|
||||||
context["title"] = f"enviPath - {current_package.name} - {current_rule.name}"
|
context["title"] = f"enviPath - {current_package.get_name()} - {current_rule.get_name()}"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "enzyme"
|
context["object_type"] = "enzyme"
|
||||||
@ -1676,7 +1696,7 @@ def package_reactions(request, package_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - Reactions"
|
context["title"] = f"enviPath - {current_package.get_name()} - Reactions"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "reaction"
|
context["object_type"] = "reaction"
|
||||||
@ -1700,7 +1720,7 @@ def package_reactions(request, package_uuid):
|
|||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{
|
{
|
||||||
"objects": [
|
"objects": [
|
||||||
{"name": pw.name, "url": pw.url, "reviewed": current_package.reviewed}
|
{"name": pw.get_name(), "url": pw.url, "reviewed": current_package.reviewed}
|
||||||
for pw in (
|
for pw in (
|
||||||
reviewed_reaction_qs
|
reviewed_reaction_qs
|
||||||
if current_package.reviewed
|
if current_package.reviewed
|
||||||
@ -1741,7 +1761,9 @@ def package_reaction(request, package_uuid, reaction_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - {current_reaction.name}"
|
context["title"] = (
|
||||||
|
f"enviPath - {current_package.get_name()} - {current_reaction.get_name()}"
|
||||||
|
)
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "reaction"
|
context["object_type"] = "reaction"
|
||||||
@ -1824,7 +1846,7 @@ def package_pathways(request, package_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - Pathways"
|
context["title"] = f"enviPath - {current_package.get_name()} - Pathways"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "pathway"
|
context["object_type"] = "pathway"
|
||||||
@ -1846,7 +1868,7 @@ def package_pathways(request, package_uuid):
|
|||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{
|
{
|
||||||
"objects": [
|
"objects": [
|
||||||
{"name": pw.name, "url": pw.url, "reviewed": current_package.reviewed}
|
{"name": pw.get_name(), "url": pw.url, "reviewed": current_package.reviewed}
|
||||||
for pw in (
|
for pw in (
|
||||||
reviewed_pathway_qs
|
reviewed_pathway_qs
|
||||||
if current_package.reviewed
|
if current_package.reviewed
|
||||||
@ -1953,7 +1975,7 @@ def package_pathway(request, package_uuid, pathway_uuid):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if request.GET.get("download", False) == "true":
|
if request.GET.get("download", False) == "true":
|
||||||
filename = f"{current_pathway.name.replace(' ', '_')}_{current_pathway.uuid}.csv"
|
filename = f"{current_pathway.get_name().replace(' ', '_')}_{current_pathway.uuid}.csv"
|
||||||
csv_pw = current_pathway.to_csv()
|
csv_pw = current_pathway.to_csv()
|
||||||
response = HttpResponse(csv_pw, content_type="text/csv")
|
response = HttpResponse(csv_pw, content_type="text/csv")
|
||||||
response["Content-Disposition"] = f'attachment; filename="{filename}"'
|
response["Content-Disposition"] = f'attachment; filename="{filename}"'
|
||||||
@ -1973,7 +1995,7 @@ def package_pathway(request, package_uuid, pathway_uuid):
|
|||||||
current_user, identify_missing_rules, [current_pathway.pk], rule_package.pk
|
current_user, identify_missing_rules, [current_pathway.pk], rule_package.pk
|
||||||
)
|
)
|
||||||
|
|
||||||
filename = f"{current_pathway.name.replace(' ', '_')}_{current_pathway.uuid}.csv"
|
filename = f"{current_pathway.get_name().replace(' ', '_')}_{current_pathway.uuid}.csv"
|
||||||
response = HttpResponse(res, content_type="text/csv")
|
response = HttpResponse(res, content_type="text/csv")
|
||||||
response["Content-Disposition"] = f'attachment; filename="{filename}"'
|
response["Content-Disposition"] = f'attachment; filename="{filename}"'
|
||||||
|
|
||||||
@ -1996,7 +2018,7 @@ def package_pathway(request, package_uuid, pathway_uuid):
|
|||||||
).get(uuid=pathway_uuid)
|
).get(uuid=pathway_uuid)
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - {current_pathway.name}"
|
context["title"] = f"enviPath - {current_package.get_name()} - {current_pathway.get_name()}"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "pathway"
|
context["object_type"] = "pathway"
|
||||||
@ -2008,9 +2030,9 @@ def package_pathway(request, package_uuid, pathway_uuid):
|
|||||||
context["breadcrumbs"] = [
|
context["breadcrumbs"] = [
|
||||||
{"Home": s.SERVER_URL},
|
{"Home": s.SERVER_URL},
|
||||||
{"Package": s.SERVER_URL + "/package"},
|
{"Package": s.SERVER_URL + "/package"},
|
||||||
{current_package.name: current_package.url},
|
{current_package.get_name(): current_package.url},
|
||||||
{"Pathway": current_package.url + "/pathway"},
|
{"Pathway": current_package.url + "/pathway"},
|
||||||
{current_pathway.name: current_pathway.url},
|
{current_pathway.get_name(): current_pathway.url},
|
||||||
]
|
]
|
||||||
|
|
||||||
return render(request, "objects/pathway.html", context)
|
return render(request, "objects/pathway.html", context)
|
||||||
@ -2097,16 +2119,18 @@ def package_pathway_nodes(request, package_uuid, pathway_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - {current_pathway.name} - Nodes"
|
context["title"] = (
|
||||||
|
f"enviPath - {current_package.get_name()} - {current_pathway.get_name()} - Nodes"
|
||||||
|
)
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "node"
|
context["object_type"] = "node"
|
||||||
context["breadcrumbs"] = [
|
context["breadcrumbs"] = [
|
||||||
{"Home": s.SERVER_URL},
|
{"Home": s.SERVER_URL},
|
||||||
{"Package": s.SERVER_URL + "/package"},
|
{"Package": s.SERVER_URL + "/package"},
|
||||||
{current_package.name: current_package.url},
|
{current_package.get_name(): current_package.url},
|
||||||
{"Pathway": current_package.url + "/pathway"},
|
{"Pathway": current_package.url + "/pathway"},
|
||||||
{current_pathway.name: current_pathway.url},
|
{current_pathway.get_name(): current_pathway.url},
|
||||||
{"Node": current_pathway.url + "/node"},
|
{"Node": current_pathway.url + "/node"},
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2122,7 +2146,7 @@ def package_pathway_nodes(request, package_uuid, pathway_uuid):
|
|||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{
|
{
|
||||||
"objects": [
|
"objects": [
|
||||||
{"name": pw.name, "url": pw.url, "reviewed": current_package.reviewed}
|
{"name": pw.get_name(), "url": pw.url, "reviewed": current_package.reviewed}
|
||||||
for pw in (
|
for pw in (
|
||||||
reviewed_node_qs if current_package.reviewed else unreviewed_node_qs
|
reviewed_node_qs if current_package.reviewed else unreviewed_node_qs
|
||||||
)
|
)
|
||||||
@ -2196,7 +2220,7 @@ def package_pathway_node(request, package_uuid, pathway_uuid, node_uuid):
|
|||||||
return HttpResponse(svg_data, content_type="image/svg+xml")
|
return HttpResponse(svg_data, content_type="image/svg+xml")
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - {current_pathway.name}"
|
context["title"] = f"enviPath - {current_package.get_name()} - {current_pathway.get_name()}"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "pathway"
|
context["object_type"] = "pathway"
|
||||||
@ -2204,11 +2228,11 @@ def package_pathway_node(request, package_uuid, pathway_uuid, node_uuid):
|
|||||||
context["breadcrumbs"] = [
|
context["breadcrumbs"] = [
|
||||||
{"Home": s.SERVER_URL},
|
{"Home": s.SERVER_URL},
|
||||||
{"Package": s.SERVER_URL + "/package"},
|
{"Package": s.SERVER_URL + "/package"},
|
||||||
{current_package.name: current_package.url},
|
{current_package.get_name(): current_package.url},
|
||||||
{"Pathway": current_package.url + "/pathway"},
|
{"Pathway": current_package.url + "/pathway"},
|
||||||
{current_pathway.name: current_pathway.url},
|
{current_pathway.get_name(): current_pathway.url},
|
||||||
{"Node": current_pathway.url + "/node"},
|
{"Node": current_pathway.url + "/node"},
|
||||||
{current_node.name: current_node.url},
|
{current_node.get_name(): current_node.url},
|
||||||
]
|
]
|
||||||
|
|
||||||
context["node"] = current_node
|
context["node"] = current_node
|
||||||
@ -2261,16 +2285,18 @@ def package_pathway_edges(request, package_uuid, pathway_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - {current_pathway.name} - Edges"
|
context["title"] = (
|
||||||
|
f"enviPath - {current_package.get_name()} - {current_pathway.get_name()} - Edges"
|
||||||
|
)
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "edge"
|
context["object_type"] = "edge"
|
||||||
context["breadcrumbs"] = [
|
context["breadcrumbs"] = [
|
||||||
{"Home": s.SERVER_URL},
|
{"Home": s.SERVER_URL},
|
||||||
{"Package": s.SERVER_URL + "/package"},
|
{"Package": s.SERVER_URL + "/package"},
|
||||||
{current_package.name: current_package.url},
|
{current_package.get_name(): current_package.url},
|
||||||
{"Pathway": current_package.url + "/pathway"},
|
{"Pathway": current_package.url + "/pathway"},
|
||||||
{current_pathway.name: current_pathway.url},
|
{current_pathway.get_name(): current_pathway.url},
|
||||||
{"Edge": current_pathway.url + "/edge"},
|
{"Edge": current_pathway.url + "/edge"},
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2286,7 +2312,7 @@ def package_pathway_edges(request, package_uuid, pathway_uuid):
|
|||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{
|
{
|
||||||
"objects": [
|
"objects": [
|
||||||
{"name": pw.name, "url": pw.url, "reviewed": current_package.reviewed}
|
{"name": pw.get_name(), "url": pw.url, "reviewed": current_package.reviewed}
|
||||||
for pw in (
|
for pw in (
|
||||||
reviewed_edge_qs if current_package.reviewed else unreviewed_edge_qs
|
reviewed_edge_qs if current_package.reviewed else unreviewed_edge_qs
|
||||||
)
|
)
|
||||||
@ -2338,7 +2364,7 @@ def package_pathway_edge(request, package_uuid, pathway_uuid, edge_uuid):
|
|||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = (
|
context["title"] = (
|
||||||
f"enviPath - {current_package.name} - {current_pathway.name} - {current_edge.edge_label.name}"
|
f"enviPath - {current_package.get_name()} - {current_pathway.get_name()} - {current_edge.edge_label.get_name()}"
|
||||||
)
|
)
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
@ -2391,11 +2417,11 @@ def package_scenarios(request, package_uuid):
|
|||||||
"all", False
|
"all", False
|
||||||
):
|
):
|
||||||
scens = Scenario.objects.filter(package=current_package).order_by("name")
|
scens = Scenario.objects.filter(package=current_package).order_by("name")
|
||||||
res = [{"name": s_.name, "url": s_.url, "uuid": s_.uuid} for s_ in scens]
|
res = [{"name": s_.get_name(), "url": s_.url, "uuid": s_.uuid} for s_ in scens]
|
||||||
return JsonResponse(res, safe=False)
|
return JsonResponse(res, safe=False)
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - Scenarios"
|
context["title"] = f"enviPath - {current_package.get_name()} - Scenarios"
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "scenario"
|
context["object_type"] = "scenario"
|
||||||
@ -2419,7 +2445,7 @@ def package_scenarios(request, package_uuid):
|
|||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{
|
{
|
||||||
"objects": [
|
"objects": [
|
||||||
{"name": pw.name, "url": pw.url, "reviewed": current_package.reviewed}
|
{"name": pw.get_name(), "url": pw.url, "reviewed": current_package.reviewed}
|
||||||
for pw in (
|
for pw in (
|
||||||
reviewed_scenario_qs
|
reviewed_scenario_qs
|
||||||
if current_package.reviewed
|
if current_package.reviewed
|
||||||
@ -2511,7 +2537,9 @@ def package_scenario(request, package_uuid, scenario_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_package.name} - {current_scenario.name}"
|
context["title"] = (
|
||||||
|
f"enviPath - {current_package.get_name()} - {current_scenario.get_name()}"
|
||||||
|
)
|
||||||
|
|
||||||
context["meta"]["current_package"] = current_package
|
context["meta"]["current_package"] = current_package
|
||||||
context["object_type"] = "scenario"
|
context["object_type"] = "scenario"
|
||||||
@ -2748,13 +2776,13 @@ def group(request, group_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_group.name}"
|
context["title"] = f"enviPath - {current_group.get_name()}"
|
||||||
|
|
||||||
context["object_type"] = "group"
|
context["object_type"] = "group"
|
||||||
context["breadcrumbs"] = [
|
context["breadcrumbs"] = [
|
||||||
{"Home": s.SERVER_URL},
|
{"Home": s.SERVER_URL},
|
||||||
{"Group": s.SERVER_URL + "/group"},
|
{"Group": s.SERVER_URL + "/group"},
|
||||||
{current_group.name: current_group.url},
|
{current_group.get_name(): current_group.url},
|
||||||
]
|
]
|
||||||
|
|
||||||
context["group"] = current_group
|
context["group"] = current_group
|
||||||
@ -2909,13 +2937,13 @@ def setting(request, setting_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = f"enviPath - {current_setting.name}"
|
context["title"] = f"enviPath - {current_setting.get_name()}"
|
||||||
|
|
||||||
context["object_type"] = "setting"
|
context["object_type"] = "setting"
|
||||||
context["breadcrumbs"] = [
|
context["breadcrumbs"] = [
|
||||||
{"Home": s.SERVER_URL},
|
{"Home": s.SERVER_URL},
|
||||||
{"Setting": s.SERVER_URL + "/setting"},
|
{"Setting": s.SERVER_URL + "/setting"},
|
||||||
{f"{current_setting.name}": current_setting.url},
|
{f"{current_setting.get_name()}": current_setting.url},
|
||||||
]
|
]
|
||||||
|
|
||||||
context["setting"] = current_setting
|
context["setting"] = current_setting
|
||||||
@ -2964,8 +2992,8 @@ def jobs(request):
|
|||||||
|
|
||||||
target_package = PackageManager.create_package(
|
target_package = PackageManager.create_package(
|
||||||
current_user,
|
current_user,
|
||||||
f"Autogenerated Package for Pathway Engineering of {pathway_to_engineer.name}",
|
f"Autogenerated Package for Pathway Engineering of {pathway_to_engineer.get_name()}",
|
||||||
f"This Package was generated automatically for the engineering Task of {pathway_to_engineer.name}.",
|
f"This Package was generated automatically for the engineering Task of {pathway_to_engineer.get_name()}.",
|
||||||
)
|
)
|
||||||
|
|
||||||
from .tasks import dispatch, engineer_pathways
|
from .tasks import dispatch, engineer_pathways
|
||||||
@ -3019,7 +3047,7 @@ def jobs(request):
|
|||||||
"This Package was generated automatically for the batch prediction task.",
|
"This Package was generated automatically for the batch prediction task.",
|
||||||
)
|
)
|
||||||
|
|
||||||
from .tasks import dispatch, batch_predict
|
from .tasks import batch_predict, dispatch
|
||||||
|
|
||||||
res = dispatch(
|
res = dispatch(
|
||||||
current_user,
|
current_user,
|
||||||
@ -3057,6 +3085,8 @@ def job(request, job_uuid):
|
|||||||
|
|
||||||
if job.job_name == "batch_predict":
|
if job.job_name == "batch_predict":
|
||||||
filename = f"{job.job_name.replace(' ', '_')}_{job.task_id}.csv"
|
filename = f"{job.job_name.replace(' ', '_')}_{job.task_id}.csv"
|
||||||
|
elif job.job_name == "identify_missing_rules":
|
||||||
|
filename = f"{job.job_name.replace(' ', '_')}_{job.task_id}.csv"
|
||||||
else:
|
else:
|
||||||
raise BadRequest("Result is not downloadable!")
|
raise BadRequest("Result is not downloadable!")
|
||||||
|
|
||||||
|
|||||||
3
pnpm-workspace.yaml
Normal file
3
pnpm-workspace.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
onlyBuiltDependencies:
|
||||||
|
- '@parcel/watcher'
|
||||||
|
- '@tailwindcss/oxide'
|
||||||
@ -393,7 +393,14 @@ function draw(pathway, elem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function edge_popup(e) {
|
function edge_popup(e) {
|
||||||
popupContent = "<a href='" + e.url + "'>" + e.name + "</a><br>";
|
popupContent = "<a href='" + e.url + "'>" + e.name + "</a><br><br>";
|
||||||
|
|
||||||
|
if (e.reaction.rules) {
|
||||||
|
console.log(e.reaction.rules);
|
||||||
|
for (var rule of e.reaction.rules) {
|
||||||
|
popupContent += "Rule <a href='" + rule.url + "'>" + rule.name + "</a><br>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (e.app_domain) {
|
if (e.app_domain) {
|
||||||
adcontent = "<p>";
|
adcontent = "<p>";
|
||||||
|
|||||||
@ -176,8 +176,8 @@
|
|||||||
href="#"
|
href="#"
|
||||||
class="example-link hover:text-primary cursor-pointer"
|
class="example-link hover:text-primary cursor-pointer"
|
||||||
title="load example"
|
title="load example"
|
||||||
@click.prevent="loadExample('CC(C)CC1=CC=C(C=C1)C(C)C(=O)O', $el)"
|
@click.prevent="loadExample('COC(=O)[C@H](CC1=CC=CC=C1)NC(=O)[C@H](CC(=O)O)N', $el)"
|
||||||
>Ibuprofen</a
|
>Aspartame</a
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<a
|
<a
|
||||||
|
|||||||
@ -85,6 +85,55 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if compound_structure.half_lifes %}
|
||||||
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
|
<input type="checkbox" />
|
||||||
|
<div class="collapse-title text-xl font-medium">Half-lives</div>
|
||||||
|
<div class="collapse-content">
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="table-zebra table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Scenario</th>
|
||||||
|
<th>Values</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for scenario, half_lifes in compound_structure.half_lifes.items %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{{ scenario.url }}" class="hover:bg-base-200"
|
||||||
|
>{{ scenario.name }}
|
||||||
|
<i>({{ scenario.package.name }})</i></a
|
||||||
|
>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<table class="table-zebra table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Scenario Type</td>
|
||||||
|
<td>{{ scenario.scenario_type }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Half-life (days)</td>
|
||||||
|
<td>{{ half_lifes.0.dt50 }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Model</td>
|
||||||
|
<td>{{ half_lifes.0.model }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if compound_structure.scenarios.all %}
|
{% if compound_structure.scenarios.all %}
|
||||||
<!-- Scenarios -->
|
<!-- Scenarios -->
|
||||||
<div class="collapse-arrow bg-base-200 collapse">
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
<div class="card bg-base-100">
|
<div class="card bg-base-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h2 class="card-title text-2xl">{{ edge.edge_label.name }}</h2>
|
<h2 class="card-title text-2xl">{{ edge.get_name }}</h2>
|
||||||
<div id="actionsButton" class="dropdown dropdown-end hidden">
|
<div id="actionsButton" class="dropdown dropdown-end hidden">
|
||||||
<div tabindex="0" role="button" class="btn btn-ghost btn-sm">
|
<div tabindex="0" role="button" class="btn btn-ghost btn-sm">
|
||||||
<svg
|
<svg
|
||||||
@ -45,6 +45,11 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<p class="mt-2">
|
||||||
|
The underlying reaction can be found
|
||||||
|
<a href="{{ edge.edge_label.url }}" class="link link-primary">here</a
|
||||||
|
>.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -103,7 +103,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% elif job.job_name == 'batch_predict' %}
|
{% elif job.job_name == 'batch_predict' or job.job_name == 'identify_missing_rules' %}
|
||||||
<div
|
<div
|
||||||
id="table-container"
|
id="table-container"
|
||||||
class="overflow-x-auto overflow-y-auto max-h-96 border rounded-lg"
|
class="overflow-x-auto overflow-y-auto max-h-96 border rounded-lg"
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
<div class="card bg-base-100">
|
<div class="card bg-base-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h2 class="card-title text-2xl">{{ node.name }}</h2>
|
<h2 class="card-title text-2xl">{{ node.get_name }}</h2>
|
||||||
<div id="actionsButton" class="dropdown dropdown-end hidden">
|
<div id="actionsButton" class="dropdown dropdown-end hidden">
|
||||||
<div tabindex="0" role="button" class="btn btn-ghost btn-sm">
|
<div tabindex="0" role="button" class="btn btn-ghost btn-sm">
|
||||||
<svg
|
<svg
|
||||||
@ -54,28 +54,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Description -->
|
|
||||||
<div class="collapse-arrow bg-base-200 collapse">
|
|
||||||
<input type="checkbox" checked />
|
|
||||||
<div class="collapse-title text-xl font-medium">Description</div>
|
|
||||||
<div class="collapse-content">{{ node.description }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if node.aliases %}
|
|
||||||
<!-- Aliases -->
|
|
||||||
<div class="collapse-arrow bg-base-200 collapse">
|
|
||||||
<input type="checkbox" checked />
|
|
||||||
<div class="collapse-title text-xl font-medium">Aliases</div>
|
|
||||||
<div class="collapse-content">
|
|
||||||
<ul class="menu bg-base-100 rounded-box">
|
|
||||||
{% for alias in node.aliases %}
|
|
||||||
<li><a class="hover:bg-base-200">{{ alias }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Image Representation -->
|
<!-- Image Representation -->
|
||||||
<div class="collapse-arrow bg-base-200 collapse">
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
<input type="checkbox" checked />
|
<input type="checkbox" checked />
|
||||||
@ -96,6 +74,70 @@
|
|||||||
<div class="collapse-content">{{ node.default_node_label.smiles }}</div>
|
<div class="collapse-content">{{ node.default_node_label.smiles }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if node.default_node_label.aliases %}
|
||||||
|
<!-- Aliases -->
|
||||||
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
|
<input type="checkbox" checked />
|
||||||
|
<div class="collapse-title text-xl font-medium">Aliases</div>
|
||||||
|
<div class="collapse-content">
|
||||||
|
<ul class="menu bg-base-100 rounded-box">
|
||||||
|
{% for alias in node.default_node_label.aliases %}
|
||||||
|
<li><a class="hover:bg-base-200">{{ alias }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if node.default_node_label.half_lifes %}
|
||||||
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
|
<input type="checkbox" />
|
||||||
|
<div class="collapse-title text-xl font-medium">Half-lives</div>
|
||||||
|
<div class="collapse-content">
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="table-zebra table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Scenario</th>
|
||||||
|
<th>Values</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for scenario, half_lifes in node.default_node_label.half_lifes.items %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{{ scenario.url }}" class="hover:bg-base-200"
|
||||||
|
>{{ scenario.name }}
|
||||||
|
<i>({{ scenario.package.name }})</i></a
|
||||||
|
>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<table class="table-zebra table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Scenario Type</td>
|
||||||
|
<td>{{ scenario.scenario_type }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Half-life (days)</td>
|
||||||
|
<td>{{ half_lifes.0.dt50 }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Model</td>
|
||||||
|
<td>{{ half_lifes.0.model }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if node.scenarios.all %}
|
{% if node.scenarios.all %}
|
||||||
<!-- Scenarios -->
|
<!-- Scenarios -->
|
||||||
<div class="collapse-arrow bg-base-200 collapse">
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
|
|||||||
Reference in New Issue
Block a user