moved cleaning to create where possible. Changed nh_safe to safe as we assume everything was cleaned in the first place

This commit is contained in:
Liam Brydon
2025-11-06 09:46:30 +13:00
parent c663eaf7bd
commit 4524b8fdf3
49 changed files with 232 additions and 263 deletions

View File

@ -92,7 +92,7 @@ TEMPLATES = [
}, },
] ]
ALLOWED_HTML_TAGS = {'b', 'i', 'u', 'a'} ALLOWED_HTML_TAGS = {'b', 'i', 'u', 'a', 'br', 'em', 'mark', 'p', 's', 'strong'}
WSGI_APPLICATION = "envipath.wsgi.application" WSGI_APPLICATION = "envipath.wsgi.application"

View File

@ -4,6 +4,7 @@ import json
from typing import Union, List, Optional, Set, Dict, Any from typing import Union, List, Optional, Set, Dict, Any
from uuid import UUID from uuid import UUID
import nh3
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.db import transaction from django.db import transaction
from django.conf import settings as s from django.conf import settings as s
@ -184,6 +185,12 @@ class UserManager(object):
def create_user( def create_user(
username, email, password, set_setting=True, add_to_group=True, *args, **kwargs username, email, password, set_setting=True, add_to_group=True, *args, **kwargs
): ):
# Clean for potential XSS
clean_username = nh3.clean(username).strip()
clean_email = nh3.clean(email).strip()
if clean_username != username or clean_email != email:
# This will be caught by the try in view.py/register
raise ValueError("Invalid username or password")
# avoid circular import :S # avoid circular import :S
from .tasks import send_registration_mail from .tasks import send_registration_mail
@ -261,8 +268,9 @@ class GroupManager(object):
@staticmethod @staticmethod
def create_group(current_user, name, description): def create_group(current_user, name, description):
g = Group() g = Group()
g.name = name # Clean for potential XSS
g.description = description g.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
g.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
g.owner = current_user g.owner = current_user
g.save() g.save()
@ -517,8 +525,9 @@ class PackageManager(object):
@transaction.atomic @transaction.atomic
def create_package(current_user, name: str, description: str = None): def create_package(current_user, name: str, description: str = None):
p = Package() p = Package()
p.name = name # Clean for potential XSS
p.description = description p.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
p.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
p.save() p.save()
up = UserPackagePermission() up = UserPackagePermission()
@ -1051,28 +1060,29 @@ class SettingManager(object):
model: EPModel = None, model: EPModel = None,
model_threshold: float = None, model_threshold: float = None,
): ):
s = Setting() new_s = Setting()
s.name = name # Clean for potential XSS
s.description = description new_s.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
s.max_nodes = max_nodes new_s.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
s.max_depth = max_depth new_s.max_nodes = max_nodes
s.model = model new_s.max_depth = max_depth
s.model_threshold = model_threshold new_s.model = model
new_s.model_threshold = model_threshold
s.save() new_s.save()
if rule_packages is not None: if rule_packages is not None:
for r in rule_packages: for r in rule_packages:
s.rule_packages.add(r) new_s.rule_packages.add(r)
s.save() new_s.save()
usp = UserSettingPermission() usp = UserSettingPermission()
usp.user = user usp.user = user
usp.setting = s usp.setting = new_s
usp.permission = Permission.ALL[0] usp.permission = Permission.ALL[0]
usp.save() usp.save()
return s return new_s
@staticmethod @staticmethod
def get_default_setting(user: User): def get_default_setting(user: User):

View File

@ -11,6 +11,7 @@ from typing import Union, List, Optional, Dict, Tuple, Set, Any
from uuid import uuid4 from uuid import uuid4
import math import math
import joblib import joblib
import nh3
import numpy as np import numpy as np
from django.conf import settings as s from django.conf import settings as s
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
@ -790,12 +791,11 @@ class Compound(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdentifierMixin
if name is None or name.strip() == "": if name is None or name.strip() == "":
name = f"Compound {Compound.objects.filter(package=package).count() + 1}" name = f"Compound {Compound.objects.filter(package=package).count() + 1}"
# Clean for potential XSS
c.name = name c.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
# 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
if description is not None and description.strip() != "": if description is not None and description.strip() != "":
c.description = description.strip() c.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
c.save() c.save()
@ -967,11 +967,11 @@ class CompoundStructure(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdenti
raise ValueError("Unpersisted Compound! Persist compound first!") raise ValueError("Unpersisted Compound! Persist compound first!")
cs = CompoundStructure() cs = CompoundStructure()
# Clean for potential XSS
if name is not None: if name is not None:
cs.name = name cs.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if description is not None: if description is not None:
cs.description = description cs.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
cs.smiles = smiles cs.smiles = smiles
cs.compound = compound cs.compound = compound
@ -1144,18 +1144,18 @@ class SimpleAmbitRule(SimpleRule):
if name is None or name.strip() == "": if name is None or name.strip() == "":
name = f"Rule {Rule.objects.filter(package=package).count() + 1}" name = f"Rule {Rule.objects.filter(package=package).count() + 1}"
r.name = name # Clean for potential XSS
r.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if description is not None and description.strip() != "": if description is not None and description.strip() != "":
r.description = description r.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
r.smirks = smirks r.smirks = nh3.clean(smirks).strip()
if reactant_filter_smarts is not None and reactant_filter_smarts.strip() != "": if reactant_filter_smarts is not None and reactant_filter_smarts.strip() != "":
r.reactant_filter_smarts = reactant_filter_smarts r.reactant_filter_smarts = nh3.clean(reactant_filter_smarts).strip()
if product_filter_smarts is not None and product_filter_smarts.strip() != "": if product_filter_smarts is not None and product_filter_smarts.strip() != "":
r.product_filter_smarts = product_filter_smarts r.product_filter_smarts = nh3.clean(product_filter_smarts).strip()
r.save() r.save()
return r return r
@ -1356,12 +1356,11 @@ class Reaction(EnviPathModel, AliasMixin, ScenarioMixin, ReactionIdentifierMixin
r = Reaction() r = Reaction()
r.package = package r.package = package
# Clean for potential XSS
if name is not None and name.strip() != "": if name is not None and name.strip() != "":
r.name = name 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 = description r.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
r.multi_step = multi_step r.multi_step = multi_step
@ -1663,10 +1662,10 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
if name is None or name.strip() == "": if name is None or name.strip() == "":
name = f"Pathway {Pathway.objects.filter(package=package).count() + 1}" name = f"Pathway {Pathway.objects.filter(package=package).count() + 1}"
pw.name = name # Clean for potential XSS
pw.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if description is not None and description.strip() != "": if description is not None and description.strip() != "":
pw.description = description pw.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
pw.save() pw.save()
try: try:
@ -1961,11 +1960,15 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin):
for node in end_nodes: for node in end_nodes:
e.end_nodes.add(node) e.end_nodes.add(node)
# Clean for potential XSS
# Cleaning technically not needed as it is also done in Reaction.create, including it here for consistency
if name is None: if name is None:
name = f"Reaction {pathway.package.reactions.count() + 1}" name = f"Reaction {pathway.package.reactions.count() + 1}"
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if description is None: if description is None:
description = s.DEFAULT_VALUES["description"] description = s.DEFAULT_VALUES["description"]
description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
r = Reaction.create( r = Reaction.create(
pathway.package, pathway.package,
@ -2482,10 +2485,10 @@ class RuleBasedRelativeReasoning(PackageBasedModel):
if name is None or name.strip() == "": if name is None or name.strip() == "":
name = f"RuleBasedRelativeReasoning {RuleBasedRelativeReasoning.objects.filter(package=package).count() + 1}" name = f"RuleBasedRelativeReasoning {RuleBasedRelativeReasoning.objects.filter(package=package).count() + 1}"
rbrr.name = name # Clean for potential XSS
rbrr.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if description is not None and description.strip() != "": if description is not None and description.strip() != "":
rbrr.description = description rbrr.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
if threshold is None or (threshold <= 0 or 1 <= threshold): if threshold is None or (threshold <= 0 or 1 <= threshold):
raise ValueError("Threshold must be a float between 0 and 1.") raise ValueError("Threshold must be a float between 0 and 1.")
@ -2591,10 +2594,10 @@ class MLRelativeReasoning(PackageBasedModel):
if name is None or name.strip() == "": if name is None or name.strip() == "":
name = f"MLRelativeReasoning {MLRelativeReasoning.objects.filter(package=package).count() + 1}" name = f"MLRelativeReasoning {MLRelativeReasoning.objects.filter(package=package).count() + 1}"
mlrr.name = name # Clean for potential XSS
mlrr.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if description is not None and description.strip() != "": if description is not None and description.strip() != "":
mlrr.description = description mlrr.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
if threshold is None or (threshold <= 0 or 1 <= threshold): if threshold is None or (threshold <= 0 or 1 <= threshold):
raise ValueError("Threshold must be a float between 0 and 1.") raise ValueError("Threshold must be a float between 0 and 1.")
@ -2954,10 +2957,10 @@ class EnviFormer(PackageBasedModel):
if name is None or name.strip() == "": if name is None or name.strip() == "":
name = f"EnviFormer {EnviFormer.objects.filter(package=package).count() + 1}" name = f"EnviFormer {EnviFormer.objects.filter(package=package).count() + 1}"
mod.name = name # Clean for potential XSS
mod.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if description is not None and description.strip() != "": if description is not None and description.strip() != "":
mod.description = description mod.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
if threshold is None or (threshold <= 0 or 1 <= threshold): if threshold is None or (threshold <= 0 or 1 <= threshold):
raise ValueError("Threshold must be a float between 0 and 1.") raise ValueError("Threshold must be a float between 0 and 1.")
@ -3400,41 +3403,43 @@ class Scenario(EnviPathModel):
scenario_type: str, scenario_type: str,
additional_information: List["EnviPyModel"], additional_information: List["EnviPyModel"],
): ):
s = Scenario() new_s = Scenario()
s.package = package new_s.package = package
if name is None or name.strip() == "": if name is None or name.strip() == "":
name = f"Scenario {Scenario.objects.filter(package=package).count() + 1}" name = f"Scenario {Scenario.objects.filter(package=package).count() + 1}"
s.name = name new_s.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if description is not None and description.strip() != "": if description is not None and description.strip() != "":
s.description = description new_s.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
if scenario_date is not None and scenario_date.strip() != "": if scenario_date is not None and scenario_date.strip() != "":
s.scenario_date = scenario_date new_s.scenario_date = nh3.clean(scenario_date).strip()
if scenario_type is not None and scenario_type.strip() != "": if scenario_type is not None and scenario_type.strip() != "":
s.scenario_type = scenario_type new_s.scenario_type = scenario_type
add_inf = defaultdict(list) add_inf = defaultdict(list)
for info in additional_information: for info in additional_information:
cls_name = info.__class__.__name__ cls_name = info.__class__.__name__
ai_data = json.loads(info.model_dump_json()) # Clean for potential XSS hidden in the additional information fields.
ai_data = json.loads(nh3.clean(info.model_dump_json()).strip())
ai_data["uuid"] = f"{uuid4()}" ai_data["uuid"] = f"{uuid4()}"
add_inf[cls_name].append(ai_data) add_inf[cls_name].append(ai_data)
s.additional_information = add_inf new_s.additional_information = add_inf
s.save() new_s.save()
return s return new_s
@transaction.atomic @transaction.atomic
def add_additional_information(self, data: "EnviPyModel"): def add_additional_information(self, data: "EnviPyModel"):
cls_name = data.__class__.__name__ cls_name = data.__class__.__name__
ai_data = json.loads(data.model_dump_json()) # Clean for potential XSS hidden in the additional information fields.
ai_data = json.loads(nh3.clean(data.model_dump_json()).strip())
ai_data["uuid"] = f"{uuid4()}" ai_data["uuid"] = f"{uuid4()}"
if cls_name not in self.additional_information: if cls_name not in self.additional_information:
@ -3469,7 +3474,8 @@ class Scenario(EnviPathModel):
new_ais = defaultdict(list) new_ais = defaultdict(list)
for k, vals in data.items(): for k, vals in data.items():
for v in vals: for v in vals:
ai_data = json.loads(v.model_dump_json()) # Clean for potential XSS hidden in the additional information fields.
ai_data = json.loads(nh3.clean(v.model_dump_json()).strip())
if hasattr(v, "uuid"): if hasattr(v, "uuid"):
ai_data["uuid"] = str(v.uuid) ai_data["uuid"] = str(v.uuid)
else: else:

View File

@ -1,7 +1,4 @@
from django import template from django import template
from django.conf import settings as s
from django.utils.safestring import mark_safe
import nh3
register = template.Library() register = template.Library()
@ -9,11 +6,3 @@ register = template.Library()
@register.filter @register.filter
def classname(obj): def classname(obj):
return obj.__class__.__name__ return obj.__class__.__name__
@register.filter(name="nh_safe")
def nh_safe(txt):
if not isinstance(txt, str):
return txt
clean_html = nh3.clean(txt, tags=s.ALLOWED_HTML_TAGS)
return mark_safe(clean_html)

View File

@ -58,16 +58,6 @@ def log_post_params(request):
logger.debug(f"{k}\t{v}") logger.debug(f"{k}\t{v}")
def clean_dict(bad_dict):
"""Check each value in a dictionary for XSS attempts"""
clean = {} # TODO: I'm not sure if this is the best way to do this.
for key, value in bad_dict.items():
if key != 'csrfmiddlewaretoken' and isinstance(value, str):
value = nh3.clean(value, tags=s.ALLOWED_HTML_TAGS)
clean[key] = value
return clean
def error(request, message: str, detail: str, code: int = 400): def error(request, message: str, detail: str, code: int = 400):
context = get_base_context(request) context = get_base_context(request)
error_context = { error_context = {
@ -94,8 +84,7 @@ def login(request):
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.contrib.auth import login from django.contrib.auth import login
# Check if the cleaned username is equal to the unclean username, if not, invalid username username = request.POST.get("username").strip()
username = nh3.clean(request.POST.get("username")).strip()
if username != request.POST.get("username").strip(): if username != request.POST.get("username").strip():
context["message"] = "Login failed!" context["message"] = "Login failed!"
return render(request, "static/login.html", context) return render(request, "static/login.html", context)
@ -158,15 +147,12 @@ def register(request):
if next := request.POST.get("next"): if next := request.POST.get("next"):
context["next"] = next context["next"] = next
# We are not allowing usernames or emails to contain any html (unlike using tags=s.ALLOWED_HTML_TAGS elsewhere) username = request.POST.get("username", "").strip()
username = nh3.clean(request.POST.get("username", "")).strip() email = request.POST.get("email", "").strip()
email = nh3.clean(request.POST.get("email", "")).strip()
password = request.POST.get("password", "").strip() password = request.POST.get("password", "").strip()
rpassword = request.POST.get("rpassword", "").strip() rpassword = request.POST.get("rpassword", "").strip()
# Check if cleaned username and email are equal to the unclean, if not, invalid username or email if not (username and email and password):
if (not (username and email and password) or username != request.POST.get("username", "").strip() or
email != request.POST.get("email", "").strip()):
context["message"] = "Invalid username/email/password" context["message"] = "Invalid username/email/password"
return render(request, "static/register.html", context) return render(request, "static/register.html", context)
@ -407,11 +393,8 @@ def packages(request):
else: else:
return HttpResponseBadRequest() return HttpResponseBadRequest()
else: else:
# Clean for potential XSS package_name = request.POST.get("package-name")
package_name = nh3.clean(request.POST.get("package-name"), tags=s.ALLOWED_HTML_TAGS).strip() package_description = request.POST.get("package-description", s.DEFAULT_VALUES["description"])
package_description = nh3.clean(request.POST.get(
"package-description", s.DEFAULT_VALUES["description"]
), tags=s.ALLOWED_HTML_TAGS).strip()
created_package = PackageManager.create_package( created_package = PackageManager.create_package(
current_user, package_name, package_description current_user, package_name, package_description
@ -686,8 +669,7 @@ def search(request):
if request.method == "GET": if request.method == "GET":
package_urls = request.GET.getlist("packages") package_urls = request.GET.getlist("packages")
# Clean for potential XSS searchterm = request.GET.get("search").strip()
searchterm = nh3.clean(request.GET.get("search"), tags=s.ALLOWED_HTML_TAGS).strip()
mode = request.GET.get("mode") mode = request.GET.get("mode")
@ -789,9 +771,8 @@ def package_models(request, package_uuid):
elif request.method == "POST": elif request.method == "POST":
log_post_params(request) log_post_params(request)
# Clean for potential XSS name = request.POST.get("model-name")
name = nh3.clean(request.POST.get("model-name"), tags=s.ALLOWED_HTML_TAGS).strip() description = request.POST.get("model-description")
description = nh3.clean(request.POST.get("model-description"), tags=s.ALLOWED_HTML_TAGS).strip()
model_type = request.POST.get("model-type") model_type = request.POST.get("model-type")
@ -936,7 +917,7 @@ def package_model(request, package_uuid, model_uuid):
else: else:
return HttpResponseBadRequest() return HttpResponseBadRequest()
else: else:
# Clean for potential XSS # TODO: Move cleaning to property updater
name = nh3.clean(request.POST.get("model-name", "").strip(), tags=s.ALLOWED_HTML_TAGS).strip() name = nh3.clean(request.POST.get("model-name", "").strip(), tags=s.ALLOWED_HTML_TAGS).strip()
description = nh3.clean(request.POST.get("model-description", "").strip(), tags=s.ALLOWED_HTML_TAGS).strip() description = nh3.clean(request.POST.get("model-description", "").strip(), tags=s.ALLOWED_HTML_TAGS).strip()
@ -1040,7 +1021,7 @@ def package(request, package_uuid):
else: else:
return HttpResponseBadRequest() return HttpResponseBadRequest()
# Clean for potential XSS # TODO: Move cleaning to property updater
new_package_name = nh3.clean(request.POST.get("package-name"), tags=s.ALLOWED_HTML_TAGS).strip() new_package_name = nh3.clean(request.POST.get("package-name"), tags=s.ALLOWED_HTML_TAGS).strip()
new_package_description = nh3.clean(request.POST.get("package-description"), tags=s.ALLOWED_HTML_TAGS).strip() new_package_description = nh3.clean(request.POST.get("package-description"), tags=s.ALLOWED_HTML_TAGS).strip()
@ -1150,10 +1131,9 @@ def package_compounds(request, package_uuid):
return render(request, "collections/objects_list.html", context) return render(request, "collections/objects_list.html", context)
elif request.method == "POST": elif request.method == "POST":
# Clean for potential XSS compound_name = request.POST.get("compound-name")
compound_name = nh3.clean(request.POST.get("compound-name"), tags=s.ALLOWED_HTML_TAGS).strip()
compound_smiles = request.POST.get("compound-smiles").strip() compound_smiles = request.POST.get("compound-smiles").strip()
compound_description = nh3.clean(request.POST.get("compound-description"), tags=s.ALLOWED_HTML_TAGS).strip() compound_description = request.POST.get("compound-description")
c = Compound.create(current_package, compound_smiles, compound_name, compound_description) c = Compound.create(current_package, compound_smiles, compound_name, compound_description)
@ -1204,7 +1184,7 @@ def package_compound(request, package_uuid, compound_uuid):
return JsonResponse({"error": str(e)}, status=400) return JsonResponse({"error": str(e)}, status=400)
return JsonResponse({"success": current_compound.url}) return JsonResponse({"success": current_compound.url})
# Clean for potential XSS # TODO: Move cleaning to property updater
new_compound_name = nh3.clean(request.POST.get("compound-name", ""), tags=s.ALLOWED_HTML_TAGS).strip() new_compound_name = nh3.clean(request.POST.get("compound-name", ""), tags=s.ALLOWED_HTML_TAGS).strip()
new_compound_description = nh3.clean(request.POST.get("compound-description", ""), new_compound_description = nh3.clean(request.POST.get("compound-description", ""),
tags=s.ALLOWED_HTML_TAGS).strip() tags=s.ALLOWED_HTML_TAGS).strip()
@ -1271,10 +1251,9 @@ def package_compound_structures(request, package_uuid, compound_uuid):
return render(request, "collections/objects_list.html", context) return render(request, "collections/objects_list.html", context)
elif request.method == "POST": elif request.method == "POST":
# Clean for potential XSS structure_name = request.POST.get("structure-name")
structure_name = nh3.clean(request.POST.get("structure-name"), tags=s.ALLOWED_HTML_TAGS).strip()
structure_smiles = request.POST.get("structure-smiles").strip() structure_smiles = request.POST.get("structure-smiles").strip()
structure_description = nh3.clean(request.POST.get("structure-description"), tags=s.ALLOWED_HTML_TAGS).strip() structure_description = request.POST.get("structure-description")
cs = current_compound.add_structure(structure_smiles, structure_name, structure_description) cs = current_compound.add_structure(structure_smiles, structure_name, structure_description)
@ -1334,7 +1313,7 @@ def package_compound_structure(request, package_uuid, compound_uuid, structure_u
return redirect(current_compound.url + "/structure") return redirect(current_compound.url + "/structure")
else: else:
return HttpResponseBadRequest() return HttpResponseBadRequest()
# Clean for potential XSS # TODO: Move cleaning to property updater
new_structure_name = nh3.clean(request.POST.get("compound-structure-name", ""), new_structure_name = nh3.clean(request.POST.get("compound-structure-name", ""),
tags=s.ALLOWED_HTML_TAGS).strip() tags=s.ALLOWED_HTML_TAGS).strip()
new_structure_description = nh3.clean(request.POST.get("compound-structure-description", ""), new_structure_description = nh3.clean(request.POST.get("compound-structure-description", ""),
@ -1431,9 +1410,8 @@ def package_rules(request, package_uuid):
log_post_params(request) log_post_params(request)
# Generic params # Generic params
# Clean for potential XSS rule_name = request.POST.get("rule-name")
rule_name = nh3.clean(request.POST.get("rule-name"), tags=s.ALLOWED_HTML_TAGS).strip() rule_description = request.POST.get("rule-description")
rule_description = nh3.clean(request.POST.get("rule-description"), tags=s.ALLOWED_HTML_TAGS).strip()
rule_type = request.POST.get("rule-type") rule_type = request.POST.get("rule-type")
@ -1441,14 +1419,10 @@ def package_rules(request, package_uuid):
# Obtain parameters as required by rule type # Obtain parameters as required by rule type
if rule_type == "SimpleAmbitRule": if rule_type == "SimpleAmbitRule":
# Clean for potential XSS
params["smirks"] = request.POST.get("rule-smirks").strip() params["smirks"] = request.POST.get("rule-smirks").strip()
params["reactant_filter_smarts"] = nh3.clean(request.POST.get("rule-reactant-smarts"), params["reactant_filter_smarts"] = request.POST.get("rule-reactant-smarts")
tags=s.ALLOWED_HTML_TAGS).strip() params["product_filter_smarts"] = request.POST.get("rule-product-smarts")
params["product_filter_smarts"] = nh3.clean(request.POST.get("rule-product-smarts"),
tags=s.ALLOWED_HTML_TAGS).strip()
elif rule_type == "SimpleRDKitRule": elif rule_type == "SimpleRDKitRule":
# Clean for potential XSS
params["reaction_smarts"] = request.POST.get("rule-reaction-smarts").strip() params["reaction_smarts"] = request.POST.get("rule-reaction-smarts").strip()
elif rule_type == "ParallelRule": elif rule_type == "ParallelRule":
pass pass
@ -1542,7 +1516,7 @@ def package_rule(request, package_uuid, rule_uuid):
return JsonResponse({"success": current_rule.url}) return JsonResponse({"success": current_rule.url})
# Clean for potential XSS # TODO: Move cleaning to property updater
rule_name = nh3.clean(request.POST.get("rule-name", ""), tags=s.ALLOWED_HTML_TAGS).strip() rule_name = nh3.clean(request.POST.get("rule-name", ""), tags=s.ALLOWED_HTML_TAGS).strip()
rule_description = nh3.clean(request.POST.get("rule-description", "").strip(), tags=s.ALLOWED_HTML_TAGS).strip() rule_description = nh3.clean(request.POST.get("rule-description", "").strip(), tags=s.ALLOWED_HTML_TAGS).strip()
@ -1605,9 +1579,8 @@ def package_reactions(request, package_uuid):
return render(request, "collections/objects_list.html", context) return render(request, "collections/objects_list.html", context)
elif request.method == "POST": elif request.method == "POST":
# Clean for potential XSS reaction_name = request.POST.get("reaction-name")
reaction_name = nh3.clean(request.POST.get("reaction-name"), tags=s.ALLOWED_HTML_TAGS).strip() reaction_description = request.POST.get("reaction-description")
reaction_description = nh3.clean(request.POST.get("reaction-description"), tags=s.ALLOWED_HTML_TAGS).strip()
reactions_smirks = request.POST.get("reaction-smirks").strip() reactions_smirks = request.POST.get("reaction-smirks").strip()
educts = reactions_smirks.split(">>")[0].split(".") educts = reactions_smirks.split(">>")[0].split(".")
@ -1670,7 +1643,7 @@ def package_reaction(request, package_uuid, reaction_uuid):
return JsonResponse({"success": current_reaction.url}) return JsonResponse({"success": current_reaction.url})
# Clean for potential XSS # TODO: Move cleaning to property updater
new_reaction_name = nh3.clean(request.POST.get("reaction-name", ""), tags=s.ALLOWED_HTML_TAGS).strip() new_reaction_name = nh3.clean(request.POST.get("reaction-name", ""), tags=s.ALLOWED_HTML_TAGS).strip()
new_reaction_description = nh3.clean(request.POST.get("reaction-description", ""), new_reaction_description = nh3.clean(request.POST.get("reaction-description", ""),
tags=s.ALLOWED_HTML_TAGS).strip() tags=s.ALLOWED_HTML_TAGS).strip()
@ -1748,9 +1721,8 @@ def package_pathways(request, package_uuid):
elif request.method == "POST": elif request.method == "POST":
log_post_params(request) log_post_params(request)
# Clean for potential XSS name = request.POST.get("name")
name = nh3.clean(request.POST.get("name"), tags=s.ALLOWED_HTML_TAGS).strip() description = request.POST.get("description")
description = nh3.clean(request.POST.get("description"), tags=s.ALLOWED_HTML_TAGS).strip()
smiles = request.POST.get("smiles", "").strip() smiles = request.POST.get("smiles", "").strip()
pw_mode = request.POST.get("predict", "predict").strip() pw_mode = request.POST.get("predict", "predict").strip()
@ -1901,7 +1873,7 @@ def package_pathway(request, package_uuid, pathway_uuid):
return JsonResponse({"success": current_pathway.url}) return JsonResponse({"success": current_pathway.url})
# Clean for potential XSS # TODO: Move cleaning to property updater
pathway_name = nh3.clean(request.POST.get("pathway-name"), tags=s.ALLOWED_HTML_TAGS).strip() pathway_name = nh3.clean(request.POST.get("pathway-name"), tags=s.ALLOWED_HTML_TAGS).strip()
pathway_description = nh3.clean(request.POST.get("pathway-description"), tags=s.ALLOWED_HTML_TAGS).strip() pathway_description = nh3.clean(request.POST.get("pathway-description"), tags=s.ALLOWED_HTML_TAGS).strip()
@ -1983,9 +1955,8 @@ def package_pathway_nodes(request, package_uuid, pathway_uuid):
return render(request, "collections/objects_list.html", context) return render(request, "collections/objects_list.html", context)
elif request.method == "POST": elif request.method == "POST":
# Clean for potential XSS node_name = request.POST.get("node-name")
node_name = nh3.clean(request.POST.get("node-name"), tags=s.ALLOWED_HTML_TAGS).strip() node_description = request.POST.get("node-description")
node_description = nh3.clean(request.POST.get("node-description"), tags=s.ALLOWED_HTML_TAGS).strip()
node_smiles = request.POST.get("node-smiles").strip() node_smiles = request.POST.get("node-smiles").strip()
current_pathway.add_node(node_smiles, name=node_name, description=node_description) current_pathway.add_node(node_smiles, name=node_name, description=node_description)
@ -2116,9 +2087,8 @@ def package_pathway_edges(request, package_uuid, pathway_uuid):
elif request.method == "POST": elif request.method == "POST":
log_post_params(request) log_post_params(request)
# Clean for potential XSS edge_name = request.POST.get("edge-name")
edge_name = nh3.clean(request.POST.get("edge-name"), tags=s.ALLOWED_HTML_TAGS).strip() edge_description = request.POST.get("edge-description")
edge_description = nh3.clean(request.POST.get("edge-description"), tags=s.ALLOWED_HTML_TAGS).strip()
edge_substrates = request.POST.getlist("edge-substrates") edge_substrates = request.POST.getlist("edge-substrates")
edge_products = request.POST.getlist("edge-products") edge_products = request.POST.getlist("edge-products")
@ -2281,9 +2251,8 @@ def package_scenarios(request, package_uuid):
elif request.method == "POST": elif request.method == "POST":
log_post_params(request) log_post_params(request)
# Clean for potential XSS scenario_name = request.POST.get("scenario-name")
scenario_name = nh3.clean(request.POST.get("scenario-name"), tags=s.ALLOWED_HTML_TAGS).strip() scenario_description = request.POST.get("scenario-description")
scenario_description = nh3.clean(request.POST.get("scenario-description"), tags=s.ALLOWED_HTML_TAGS).strip()
scenario_date_year = request.POST.get("scenario-date-year") scenario_date_year = request.POST.get("scenario-date-year")
scenario_date_month = request.POST.get("scenario-date-month") scenario_date_month = request.POST.get("scenario-date-month")
@ -2297,7 +2266,7 @@ def package_scenarios(request, package_uuid):
scenario_type = request.POST.get("scenario-type") scenario_type = request.POST.get("scenario-type")
additional_information = HTMLGenerator.build_models(clean_dict(request.POST.dict())) additional_information = HTMLGenerator.build_models(request.POST.dict())
additional_information = [x for sv in additional_information.values() for x in sv] additional_information = [x for sv in additional_information.values() for x in sv]
new_scen = Scenario.create( new_scen = Scenario.create(
@ -2368,8 +2337,7 @@ def package_scenario(request, package_uuid, scenario_uuid):
current_scenario.save() current_scenario.save()
return redirect(current_scenario.url) return redirect(current_scenario.url)
elif hidden == "set-additional-information": elif hidden == "set-additional-information":
post_dict = clean_dict(request.POST.dict()) # Clean post dict inputs for potential XSS ais = HTMLGenerator.build_models(request.POST.dict())
ais = HTMLGenerator.build_models(post_dict)
if s.DEBUG: if s.DEBUG:
logger.info(ais) logger.info(ais)
@ -2377,8 +2345,7 @@ def package_scenario(request, package_uuid, scenario_uuid):
current_scenario.set_additional_information(ais) current_scenario.set_additional_information(ais)
return redirect(current_scenario.url) return redirect(current_scenario.url)
elif hidden == "add-additional-information": elif hidden == "add-additional-information":
post_dict = clean_dict(request.POST.dict()) # Clean post dict inputs for potential XSS ais = HTMLGenerator.build_models(request.POST.dict())
ais = HTMLGenerator.build_models(post_dict)
if len(ais.keys()) != 1: if len(ais.keys()) != 1:
raise ValueError( raise ValueError(
@ -2518,10 +2485,8 @@ def groups(request):
return render(request, "collections/objects_list.html", context) return render(request, "collections/objects_list.html", context)
elif request.method == "POST": elif request.method == "POST":
# Clean for potential XSS group_name = request.POST.get("group-name")
group_name = nh3.clean(request.POST.get("group-name"), tags=s.ALLOWED_HTML_TAGS).strip() group_description = request.POST.get("group-description", s.DEFAULT_VALUES["description"])
group_description = nh3.clean(request.POST.get("group-description", s.DEFAULT_VALUES["description"]),
tags=s.ALLOWED_HTML_TAGS).strip()
g = GroupManager.create_group(current_user, group_name, group_description) g = GroupManager.create_group(current_user, group_name, group_description)
@ -2611,9 +2576,8 @@ def settings(request):
logger.info("Parameters received:") logger.info("Parameters received:")
logger.info(f"{k}\t{v}") logger.info(f"{k}\t{v}")
# Clean for potential XSS name = request.POST.get("prediction-setting-name")
name = nh3.clean(request.POST.get("prediction-setting-name"), tags=s.ALLOWED_HTML_TAGS).strip() description = request.POST.get("prediction-setting-description")
description = nh3.clean(request.POST.get("prediction-setting-description"), tags=s.ALLOWED_HTML_TAGS).strip()
new_default = request.POST.get("prediction-setting-new-default", "off") == "on" new_default = request.POST.get("prediction-setting-new-default", "off") == "on"

View File

@ -28,7 +28,7 @@ dependencies = [
"scikit-learn>=1.6.1", "scikit-learn>=1.6.1",
"sentry-sdk[django]>=2.32.0", "sentry-sdk[django]>=2.32.0",
"setuptools>=80.8.0", "setuptools>=80.8.0",
"nh3==0.3.1" "nh3==0.3.2"
] ]
[tool.uv.sources] [tool.uv.sources]

View File

@ -193,7 +193,7 @@
<div class="panel-body list-group-item" id="ReviewedContent"> <div class="panel-body list-group-item" id="ReviewedContent">
{% if object_type == 'package' %} {% if object_type == 'package' %}
{% for obj in reviewed_objects %} {% for obj in reviewed_objects %}
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name|nh_safe }} <a class="list-group-item" href="{{ obj.url }}">{{ obj.name|safe }}
<span class="glyphicon glyphicon-star" aria-hidden="true" <span class="glyphicon glyphicon-star" aria-hidden="true"
style="float:right" data-toggle="tooltip" style="float:right" data-toggle="tooltip"
data-placement="top" title="" data-original-title="Reviewed"> data-placement="top" title="" data-original-title="Reviewed">
@ -202,7 +202,7 @@
{% endfor %} {% endfor %}
{% else %} {% else %}
{% for obj in reviewed_objects|slice:":50" %} {% for obj in reviewed_objects|slice:":50" %}
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name|nh_safe }}{# <i>({{ obj.package.name }})</i> #} <a class="list-group-item" href="{{ obj.url }}">{{ obj.name|safe }}{# <i>({{ obj.package.name }})</i> #}
<span class="glyphicon glyphicon-star" aria-hidden="true" <span class="glyphicon glyphicon-star" aria-hidden="true"
style="float:right" data-toggle="tooltip" style="float:right" data-toggle="tooltip"
data-placement="top" title="" data-original-title="Reviewed"> data-placement="top" title="" data-original-title="Reviewed">
@ -222,11 +222,11 @@
<div class="panel-body list-group-item" id="UnreviewedContent"> <div class="panel-body list-group-item" id="UnreviewedContent">
{% if object_type == 'package' %} {% if object_type == 'package' %}
{% for obj in unreviewed_objects %} {% for obj in unreviewed_objects %}
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name|nh_safe }}</a> <a class="list-group-item" href="{{ obj.url }}">{{ obj.name|safe }}</a>
{% endfor %} {% endfor %}
{% else %} {% else %}
{% for obj in unreviewed_objects|slice:":50" %} {% for obj in unreviewed_objects|slice:":50" %}
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name|nh_safe }}</a> <a class="list-group-item" href="{{ obj.url }}">{{ obj.name|safe }}</a>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</div> </div>
@ -237,9 +237,9 @@
<ul class='list-group'> <ul class='list-group'>
{% for obj in objects %} {% for obj in objects %}
{% if object_type == 'user' %} {% if object_type == 'user' %}
<a class="list-group-item" href="{{ obj.url }}">{{ obj.username|nh_safe }}</a> <a class="list-group-item" href="{{ obj.url }}">{{ obj.username|safe }}</a>
{% else %} {% else %}
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name|nh_safe }}</a> <a class="list-group-item" href="{{ obj.url }}">{{ obj.name|safe }}</a>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</ul> </ul>

View File

@ -27,12 +27,12 @@
{% endif %} {% endif %}
<h4 class="panel-title"> <h4 class="panel-title">
<a id="{{ obj.id }}-link" data-toggle="collapse" data-parent="#migration-detail" <a id="{{ obj.id }}-link" data-toggle="collapse" data-parent="#migration-detail"
href="#{{ obj.id }}">{{ obj.name|nh_safe }}</a> href="#{{ obj.id }}">{{ obj.name|safe }}</a>
</h4> </h4>
</div> </div>
<div id="{{ obj.id }}" class="panel-collapse collapse {% if not obj.status %}in{% endif %}"> <div id="{{ obj.id }}" class="panel-collapse collapse {% if not obj.status %}in{% endif %}">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
<a class="list-group-item" href="{{ obj.detail_url }}">{{ obj.name|nh_safe }} Migration Detail Page</a> <a class="list-group-item" href="{{ obj.detail_url }}">{{ obj.name|safe }} Migration Detail Page</a>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}

View File

@ -28,7 +28,7 @@
{% endif %} {% endif %}
<h4 class="panel-title"> <h4 class="panel-title">
<a id="{{ obj.id }}-link" data-toggle="collapse" data-parent="#migration-detail" <a id="{{ obj.id }}-link" data-toggle="collapse" data-parent="#migration-detail"
href="#{{ obj.id }}">{{ obj.name|nh_safe }}</a> href="#{{ obj.id }}">{{ obj.name|safe }}</a>
</h4> </h4>
</div> </div>
<div id="{{ obj.id }}" class="panel-collapse collapse {% if not obj.status %}in{% endif %}"> <div id="{{ obj.id }}" class="panel-collapse collapse {% if not obj.status %}in{% endif %}">

View File

@ -42,14 +42,14 @@
<option disabled>Reviewed Packages</option> <option disabled>Reviewed Packages</option>
{% for obj in meta.readable_packages %} {% for obj in meta.readable_packages %}
{% if obj.reviewed %} {% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|nh_safe }}</option> <option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<option disabled>Unreviewed Packages</option> <option disabled>Unreviewed Packages</option>
{% for obj in meta.readable_packages %} {% for obj in meta.readable_packages %}
{% if not obj.reviewed %} {% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|nh_safe }}</option> <option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</select> </select>
@ -60,14 +60,14 @@
<option disabled>Reviewed Packages</option> <option disabled>Reviewed Packages</option>
{% for obj in meta.readable_packages %} {% for obj in meta.readable_packages %}
{% if obj.reviewed %} {% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|nh_safe }}</option> <option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<option disabled>Unreviewed Packages</option> <option disabled>Unreviewed Packages</option>
{% for obj in meta.readable_packages %} {% for obj in meta.readable_packages %}
{% if not obj.reviewed %} {% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|nh_safe }}</option> <option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</select> </select>

View File

@ -112,7 +112,7 @@
<select id="settingSelect" name="settingSelect" class="form-control"> <select id="settingSelect" name="settingSelect" class="form-control">
{% for setting in available_settings %} {% for setting in available_settings %}
<option value="{{ setting.id }}">{{ setting.name|nh_safe }}</option> <option value="{{ setting.id }}">{{ setting.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
<p></p> <p></p>

View File

@ -41,14 +41,14 @@
<option disabled>Reviewed Packages</option> <option disabled>Reviewed Packages</option>
{% for obj in meta.readable_packages %} {% for obj in meta.readable_packages %}
{% if obj.reviewed %} {% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|nh_safe }}</option> <option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<option disabled>Unreviewed Packages</option> <option disabled>Unreviewed Packages</option>
{% for obj in meta.readable_packages %} {% for obj in meta.readable_packages %}
{% if not obj.reviewed %} {% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|nh_safe }}</option> <option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</select> </select>
@ -58,7 +58,7 @@
<select id="model-based-prediction-setting-model" name="model-based-prediction-setting-model" class="form-control" data-width='100%'> <select id="model-based-prediction-setting-model" name="model-based-prediction-setting-model" class="form-control" data-width='100%'>
<option disabled selected>Select the model</option> <option disabled selected>Select the model</option>
{% for m in models %} {% for m in models %}
<option value="{{ m.url }}">{{ m.name|nh_safe }}</option> <option value="{{ m.url }}">{{ m.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
<label for="model-based-prediction-setting-threshold">Threshold</label> <label for="model-based-prediction-setting-threshold">Threshold</label>

View File

@ -37,7 +37,7 @@
<select id="add_pathway_edge_substrates" name="edge-substrates" <select id="add_pathway_edge_substrates" name="edge-substrates"
data-actions-box='true' class="form-control" multiple data-width='100%'> data-actions-box='true' class="form-control" multiple data-width='100%'>
{% for n in pathway.nodes %} {% for n in pathway.nodes %}
<option data-smiles="{{ n.default_node_label.smiles }}" value="{{ n.url }}">{{ n.default_node_label.name|nh_safe }}</option> <option data-smiles="{{ n.default_node_label.smiles }}" value="{{ n.url }}">{{ n.default_node_label.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -48,7 +48,7 @@
<select id="add_pathway_edge_products" name="edge-products" <select id="add_pathway_edge_products" name="edge-products"
data-actions-box='true' class="form-control" multiple data-width='100%'> data-actions-box='true' class="form-control" multiple data-width='100%'>
{% for n in pathway.nodes %} {% for n in pathway.nodes %}
<option data-smiles="{{ n.default_node_label.smiles }}" value="{{ n.url }}">{{ n.default_node_label.name|nh_safe }}</option> <option data-smiles="{{ n.default_node_label.smiles }}" value="{{ n.url }}">{{ n.default_node_label.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>

View File

@ -20,7 +20,7 @@
data-actions-box='true' class="form-control" data-width='100%'> data-actions-box='true' class="form-control" data-width='100%'>
<option value="" disabled selected>Select Reaction to delete</option> <option value="" disabled selected>Select Reaction to delete</option>
{% for e in pathway.edges %} {% for e in pathway.edges %}
<option value="{{ e.url }}">{{ e.edge_label.name|nh_safe }}</option> <option value="{{ e.url }}">{{ e.edge_label.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
<input type="hidden" id="hidden" name="hidden" value="delete"/> <input type="hidden" id="hidden" name="hidden" value="delete"/>

View File

@ -20,7 +20,7 @@
data-actions-box='true' class="form-control" data-width='100%'> data-actions-box='true' class="form-control" data-width='100%'>
<option value="" disabled selected>Select Compound to delete</option> <option value="" disabled selected>Select Compound to delete</option>
{% for n in pathway.nodes %} {% for n in pathway.nodes %}
<option value="{{ n.url }}">{{ n.default_node_label.name|nh_safe }}</option> <option value="{{ n.url }}">{{ n.default_node_label.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
<input type="hidden" id="hidden" name="hidden" value="delete"/> <input type="hidden" id="hidden" name="hidden" value="delete"/>

View File

@ -16,12 +16,12 @@
{% csrf_token %} {% csrf_token %}
<p> <p>
<label for="compound-name">Name</label> <label for="compound-name">Name</label>
<input id="compound-name" class="form-control" name="compound-name" value="{{ compound.name|nh_safe}}"> <input id="compound-name" class="form-control" name="compound-name" value="{{ compound.name|safe}}">
</p> </p>
<p> <p>
<label for="compound-description">Description</label> <label for="compound-description">Description</label>
<input id="compound-description" type="text" class="form-control" <input id="compound-description" type="text" class="form-control"
value="{{ compound.description|nh_safe }}" value="{{ compound.description|safe }}"
name="compound-description"> name="compound-description">
</p> </p>
</form> </form>

View File

@ -16,12 +16,12 @@
{% csrf_token %} {% csrf_token %}
<p> <p>
<label for="compound-structure-name">Name</label> <label for="compound-structure-name">Name</label>
<input id="compound-structure-name" class="form-control" name="compound-structure-name" value="{{ compound_structure.name|nh_safe }}"> <input id="compound-structure-name" class="form-control" name="compound-structure-name" value="{{ compound_structure.name|safe }}">
</p> </p>
<p> <p>
<label for="compound-structure-description">Description</label> <label for="compound-structure-description">Description</label>
<input id="compound-structure-description" type="text" class="form-control" <input id="compound-structure-description" type="text" class="form-control"
value="{{ compound_structure.description|nh_safe }}" name="compound-structure-description"> value="{{ compound_structure.description|safe }}" name="compound-structure-description">
</p> </p>
</form> </form>
</div> </div>

View File

@ -40,7 +40,7 @@
{% endfor %} {% endfor %}
<option disabled>Groups</option> <option disabled>Groups</option>
{% for g in groups %} {% for g in groups %}
<option value="{{ g.url }}">{{ g.name|nh_safe }}</option> <option value="{{ g.url }}">{{ g.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
<input type="hidden" name="action" value="add"> <input type="hidden" name="action" value="add">
@ -82,7 +82,7 @@
accept-charset="UTF-8" action="" data-remote="true" method="post"> accept-charset="UTF-8" action="" data-remote="true" method="post">
{% csrf_token %} {% csrf_token %}
<div class="col-xs-8"> <div class="col-xs-8">
{{ g.name|nh_safe }} {{ g.name|safe }}
<input type="hidden" name="member" value="{{ g.url }}"/> <input type="hidden" name="member" value="{{ g.url }}"/>
<input type="hidden" name="action" value="remove"> <input type="hidden" name="action" value="remove">
</div> </div>

View File

@ -17,12 +17,12 @@
<p> <p>
<label for="model-name">Name</label> <label for="model-name">Name</label>
<input id="model-name" type="text" class="form-control" name="model-name" <input id="model-name" type="text" class="form-control" name="model-name"
value="{{ model.name|nh_safe }}"> value="{{ model.name|safe }}">
</p> </p>
<p> <p>
<label for="model-description">Description</label> <label for="model-description">Description</label>
<input id="model-description" type="text" class="form-control" name="model-description" <input id="model-description" type="text" class="form-control" name="model-description"
value="{{ model.description|nh_safe }}"> value="{{ model.description|safe }}">
</p> </p>
</form> </form>
</div> </div>

View File

@ -16,12 +16,12 @@
{% csrf_token %} {% csrf_token %}
<p> <p>
<label for="node-name">Name</label> <label for="node-name">Name</label>
<input id="node-name" class="form-control" name="node-name" value="{{ node.name|nh_safe}}"> <input id="node-name" class="form-control" name="node-name" value="{{ node.name|safe}}">
</p> </p>
<p> <p>
<label for="node-description">Description</label> <label for="node-description">Description</label>
<input id="node-description" type="text" class="form-control" <input id="node-description" type="text" class="form-control"
value="{{ node.description|nh_safe }}" value="{{ node.description|safe }}"
name="node-description"> name="node-description">
</p> </p>
</form> </form>

View File

@ -16,12 +16,12 @@
{% csrf_token %} {% csrf_token %}
<p> <p>
<label for="package-name">Name</label> <label for="package-name">Name</label>
<input id="package-name" class="form-control" name="package-name" value="{{ package.name|nh_safe}}"> <input id="package-name" class="form-control" name="package-name" value="{{ package.name|safe}}">
</p> </p>
<p> <p>
<label for="package-description">Description</label> <label for="package-description">Description</label>
<input id="package-description" type="text" class="form-control" <input id="package-description" type="text" class="form-control"
value="{{ package.description|nh_safe }}" value="{{ package.description|safe }}"
name="package-description"> name="package-description">
</p> </p>
</form> </form>

View File

@ -47,7 +47,7 @@
{% endfor %} {% endfor %}
<option disabled>Groups</option> <option disabled>Groups</option>
{% for g in groups %} {% for g in groups %}
<option value="{{ g.url }}">{{ g.name|nh_safe }}</option> <option value="{{ g.url }}">{{ g.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -101,7 +101,7 @@
accept-charset="UTF-8" action="" data-remote="true" method="post"> accept-charset="UTF-8" action="" data-remote="true" method="post">
{% csrf_token %} {% csrf_token %}
<div class="col-xs-4"> <div class="col-xs-4">
{{ gp.group.name|nh_safe }} {{ gp.group.name|safe }}
<input type="hidden" name="grantee" value="{{ gp.group.url }}"/> <input type="hidden" name="grantee" value="{{ gp.group.url }}"/>
</div> </div>
<div class="col-xs-2"> <div class="col-xs-2">

View File

@ -16,12 +16,12 @@
{% csrf_token %} {% csrf_token %}
<p> <p>
<label for="pathway-name">Name</label> <label for="pathway-name">Name</label>
<input id="pathway-name" class="form-control" name="pathway-name" value="{{ pathway.name|nh_safe }}"> <input id="pathway-name" class="form-control" name="pathway-name" value="{{ pathway.name|safe }}">
</p> </p>
<p> <p>
<label for="pathway-description">Description</label> <label for="pathway-description">Description</label>
<textarea id="pathway-description" type="text" class="form-control" name="pathway-description" <textarea id="pathway-description" type="text" class="form-control" name="pathway-description"
rows="10">{{ pathway.description|nh_safe }}</textarea> rows="10">{{ pathway.description|safe }}</textarea>
</p> </p>
</form> </form>
</div> </div>

View File

@ -33,7 +33,7 @@
<td colspan="2"> <td colspan="2">
<select id="model" name="model" class="form-control" data-width='100%'> <select id="model" name="model" class="form-control" data-width='100%'>
{% for m in models %} {% for m in models %}
<option value="{{ m.id }}" {% if user.prediction_settings.model.url == m.url %}selected{% endif %}>{{ m.name|nh_safe }}</option> <option value="{{ m.id }}" {% if user.prediction_settings.model.url == m.url %}selected{% endif %}>{{ m.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
</td> </td>

View File

@ -15,12 +15,12 @@
{% csrf_token %} {% csrf_token %}
<p> <p>
<label for="reaction-name">Name</label> <label for="reaction-name">Name</label>
<input id="reaction-name" class="form-control" name="reaction-name" value="{{ reaction.name|nh_safe }}"> <input id="reaction-name" class="form-control" name="reaction-name" value="{{ reaction.name|safe }}">
</p> </p>
<p> <p>
<label for="reaction-description">Description</label> <label for="reaction-description">Description</label>
<input id="reaction-description" type="text" class="form-control" <input id="reaction-description" type="text" class="form-control"
value="{{ reaction.description|nh_safe }}" name="reaction-description"> value="{{ reaction.description|safe }}" name="reaction-description">
</p> </p>
</form> </form>
</div> </div>

View File

@ -15,12 +15,12 @@
{% csrf_token %} {% csrf_token %}
<p> <p>
<label for="rule-name">Name</label> <label for="rule-name">Name</label>
<input id="rule-name" class="form-control" name="rule-name" value="{{ rule.name|nh_safe }}"> <input id="rule-name" class="form-control" name="rule-name" value="{{ rule.name|safe }}">
</p> </p>
<p> <p>
<label for="rule-description">Description</label> <label for="rule-description">Description</label>
<input id="rule-description" type="text" class="form-control" <input id="rule-description" type="text" class="form-control"
value="{{ rule.description|nh_safe }}" name="rule-description"> value="{{ rule.description|safe }}" name="rule-description">
</p> </p>
</form> </form>
</div> </div>

View File

@ -19,7 +19,7 @@
<select id="default-package" name="default-package" class="form-control" data-width='100%'> <select id="default-package" name="default-package" class="form-control" data-width='100%'>
<option disabled>Select a Package</option> <option disabled>Select a Package</option>
{% for p in meta.writeable_packages %} {% for p in meta.writeable_packages %}
<option value="{{ p.url }}" {% if p.id == meta.user.default_package.id %}selected{% endif %}>{{ p.name|nh_safe }}</option> <option value="{{ p.url }}" {% if p.id == meta.user.default_package.id %}selected{% endif %}>{{ p.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
</p> </p>
@ -28,7 +28,7 @@
<select id="default-group" name="default-group" class="form-control" data-width='100%'> <select id="default-group" name="default-group" class="form-control" data-width='100%'>
<option disabled>Select a Group</option> <option disabled>Select a Group</option>
{% for g in meta.available_groups %} {% for g in meta.available_groups %}
<option value="{{ g.url }}" {% if g.id == meta.user.default_group.id %}selected{% endif %}>{{ g.name|nh_safe }}</option> <option value="{{ g.url }}" {% if g.id == meta.user.default_group.id %}selected{% endif %}>{{ g.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
</p> </p>
@ -37,7 +37,7 @@
<select id="default-prediction-setting" name="default-prediction-setting" class="form-control" data-width='100%'> <select id="default-prediction-setting" name="default-prediction-setting" class="form-control" data-width='100%'>
<option disabled>Select a Setting</option> <option disabled>Select a Setting</option>
{% for s in meta.available_settings %} {% for s in meta.available_settings %}
<option value="{{ s.url }}" {% if s.id == meta.user.default_setting.id %}selected{% endif %}>{{ s.name|nh_safe }}</option> <option value="{{ s.url }}" {% if s.id == meta.user.default_setting.id %}selected{% endif %}>{{ s.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
</p> </p>

View File

@ -25,14 +25,14 @@
<option disabled>Reviewed Packages</option> <option disabled>Reviewed Packages</option>
{% for obj in meta.readable_packages %} {% for obj in meta.readable_packages %}
{% if obj.reviewed %} {% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|nh_safe }}</option> <option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<option disabled>Unreviewed Packages</option> <option disabled>Unreviewed Packages</option>
{% for obj in meta.readable_packages %} {% for obj in meta.readable_packages %}
{% if not obj.reviewed %} {% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|nh_safe }}</option> <option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</select> </select>

View File

@ -19,7 +19,7 @@
data-width='100%'> data-width='100%'>
<option disabled selected>Select Target Package</option> <option disabled selected>Select Target Package</option>
{% for p in meta.writeable_packages %} {% for p in meta.writeable_packages %}
<option value="{{ p.url }}">{{ p.name|nh_safe }}</option>` <option value="{{ p.url }}">{{ p.name|safe }}</option>`
{% endfor %} {% endfor %}
</select> </select>
<input type="hidden" name="hidden" value="copy"> <input type="hidden" name="hidden" value="copy">

View File

@ -56,7 +56,7 @@
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span> <span aria-hidden="true">×</span>
</button> </button>
<h4 class="modal-title">Set Aliases for {{ current_object.name|nh_safe }}</h4> <h4 class="modal-title">Set Aliases for {{ current_object.name|safe }}</h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form id="set_aliases_modal_form" accept-charset="UTF-8" action="{{ current_object.url }}" <form id="set_aliases_modal_form" accept-charset="UTF-8" action="{{ current_object.url }}"

View File

@ -24,7 +24,7 @@
{% if entity == object_type %} {% if entity == object_type %}
{% for db in databases %} {% for db in databases %}
<option id="db-select-{{ db.database.pk }}" data-input-placeholder="{{ db.placeholder }}" <option id="db-select-{{ db.database.pk }}" data-input-placeholder="{{ db.placeholder }}"
value="{{ db.database.id }}">{{ db.database.name|nh_safe }}</option>` value="{{ db.database.id }}">{{ db.database.name|safe }}</option>`
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}

View File

@ -8,7 +8,7 @@
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span> <span aria-hidden="true">×</span>
</button> </button>
<h4 class="modal-title">Set Scenarios for {{ current_object.name|nh_safe }}</h4> <h4 class="modal-title">Set Scenarios for {{ current_object.name|safe }}</h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div id="loading_scenario_div" class="text-center"></div> <div id="loading_scenario_div" class="text-center"></div>

View File

@ -42,7 +42,7 @@
<div class="input-group"> <div class="input-group">
<input type="hidden" name="hidden" value="delete"> <input type="hidden" name="hidden" value="delete">
<input type="hidden" name="token-id" value="{{ t.pk }}"> <input type="hidden" name="token-id" value="{{ t.pk }}">
<input type="text" class="form-control" value="{{ t.name|nh_safe }}" disabled> <input type="text" class="form-control" value="{{ t.name|safe }}" disabled>
<span class="input-group-btn"> <span class="input-group-btn">
<button type="submit" class="btn btn-danger">Delete</button> <button type="submit" class="btn btn-danger">Delete</button>
</span> </span>

View File

@ -57,7 +57,7 @@
<option disabled>Select a Setting</option> <option disabled>Select a Setting</option>
{% for s in meta.available_settings %} {% for s in meta.available_settings %}
<option value="{{ s.url }}"{% if s.id == meta.user.default_setting.id %}selected{% endif %}> <option value="{{ s.url }}"{% if s.id == meta.user.default_setting.id %}selected{% endif %}>
{{ s.name|nh_safe }}{% if s.id == meta.user.default_setting.id %} <i>(User default)</i>{% endif %} {{ s.name|safe }}{% if s.id == meta.user.default_setting.id %} <i>(User default)</i>{% endif %}
</option> </option>
{% endfor %} {% endfor %}
</select> </select>

View File

@ -14,7 +14,7 @@
<div class="panel-group" id="rule-detail"> <div class="panel-group" id="rule-detail">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ rule.name|nh_safe }} {{ rule.name|safe }}
<div id="actionsButton" <div id="actionsButton"
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;" style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
@ -30,7 +30,7 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p> <p>
{{ rule.description|nh_safe }} {{ rule.description|safe }}
</p> </p>
</div> </div>
@ -61,7 +61,7 @@
<div id="rule-reaction-patterns" class="panel-collapse collapse in"> <div id="rule-reaction-patterns" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for r in rule.srs %} {% for r in rule.srs %}
<a class="list-group-item" href="{{ r.url }}">{{ r.name|nh_safe }}</a> <a class="list-group-item" href="{{ r.url }}">{{ r.name|safe }}</a>
<div align="center"> <div align="center">
<p> <p>
{{r.as_svg|safe}} {{r.as_svg|safe}}
@ -82,7 +82,7 @@
<div id="rule-scenario" class="panel-collapse collapse in"> <div id="rule-scenario" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for s in rule.scenarios.all %} {% for s in rule.scenarios.all %}
<a class="list-group-item" href="{{ s.url }}">{{ s.name|nh_safe }} <i>({{ s.package.name|nh_safe }})</i></a> <a class="list-group-item" href="{{ s.url }}">{{ s.name|safe }} <i>({{ s.package.name|safe }})</i></a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -16,7 +16,7 @@
<div class="panel-group" id="compound-detail"> <div class="panel-group" id="compound-detail">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ compound.name|nh_safe }} {{ compound.name|safe }}
<div id="actionsButton" <div id="actionsButton"
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;" style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
@ -65,7 +65,7 @@
</div> </div>
<div id="compound-desc" class="panel-collapse collapse in"> <div id="compound-desc" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{{ compound.description|nh_safe }} {{ compound.description|safe }}
</div> </div>
</div> </div>
@ -134,7 +134,7 @@
<div id="compound-reaction" class="panel-collapse collapse in"> <div id="compound-reaction" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for r in compound.related_reactions %} {% for r in compound.related_reactions %}
<a class="list-group-item" href="{{ r.url }}">{{ r.name|nh_safe }} <i>({{ r.package.name|nh_safe }})</i></a> <a class="list-group-item" href="{{ r.url }}">{{ r.name|safe }} <i>({{ r.package.name|safe }})</i></a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -151,7 +151,7 @@
<div id="compound-pathway" class="panel-collapse collapse in"> <div id="compound-pathway" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for r in compound.related_pathways %} {% for r in compound.related_pathways %}
<a class="list-group-item" href="{{ r.url }}">{{ r.name|nh_safe }} <i>({{ r.package.name|nh_safe }})</i></a> <a class="list-group-item" href="{{ r.url }}">{{ r.name|safe }} <i>({{ r.package.name|safe }})</i></a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -168,7 +168,7 @@
<div id="compound-scenario" class="panel-collapse collapse in"> <div id="compound-scenario" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for s in compound.scenarios.all %} {% for s in compound.scenarios.all %}
<a class="list-group-item" href="{{ s.url }}">{{ s.name|nh_safe }} <i>({{ s.package.name|nh_safe }})</i></a> <a class="list-group-item" href="{{ s.url }}">{{ s.name|safe }} <i>({{ s.package.name|safe }})</i></a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -14,7 +14,7 @@
<div class="panel-group" id="compound-structure-detail"> <div class="panel-group" id="compound-structure-detail">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ compound_structure.name|nh_safe }} {{ compound_structure.name|safe }}
<div id="actionsButton" <div id="actionsButton"
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;" style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
@ -29,7 +29,7 @@
</div> </div>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p> {{ compound_structure.description|nh_safe }} </p> <p> {{ compound_structure.description|safe }} </p>
</div> </div>
<!-- Image --> <!-- Image -->
@ -87,7 +87,7 @@
<div id="compound-structure-scenario" class="panel-collapse collapse in"> <div id="compound-structure-scenario" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for s in compound_structure.scenarios.all %} {% for s in compound_structure.scenarios.all %}
<a class="list-group-item" href="{{ s.url }}">{{ s.name|nh_safe }} <i>({{ s.package.name|nh_safe }})</i></a> <a class="list-group-item" href="{{ s.url }}">{{ s.name|safe }} <i>({{ s.package.name|safe }})</i></a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -13,7 +13,7 @@
<div class="panel-group" id="edge-detail"> <div class="panel-group" id="edge-detail">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ edge.edge_label.name|nh_safe }} {{ edge.edge_label.name|safe }}
<div id="actionsButton" <div id="actionsButton"
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;" style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
@ -37,7 +37,7 @@
</div> </div>
<div id="edge-desc" class="panel-collapse collapse in"> <div id="edge-desc" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{{ edge.description|nh_safe }} {{ edge.description|safe }}
</div> </div>
</div> </div>
@ -83,12 +83,12 @@
<div id="edge-description-smiles" class="panel-collapse collapse in"> <div id="edge-description-smiles" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for educt in edge.start_nodes.all %} {% for educt in edge.start_nodes.all %}
<a class="btn btn-default" href="{{ educt.url }}">{{ educt.name|nh_safe }}</a> <a class="btn btn-default" href="{{ educt.url }}">{{ educt.name|safe }}</a>
{% endfor %} {% endfor %}
<span class="glyphicon glyphicon-arrow-right" style="margin-left:5em;margin-right:5em;" <span class="glyphicon glyphicon-arrow-right" style="margin-left:5em;margin-right:5em;"
aria-hidden="true"></span> aria-hidden="true"></span>
{% for product in edge.end_nodes.all %} {% for product in edge.end_nodes.all %}
<a class="btn btn-default" href="{{ product.url }}">{{ product.name|nh_safe }}</a> <a class="btn btn-default" href="{{ product.url }}">{{ product.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -117,7 +117,7 @@
<div id="edge-rules" class="panel-collapse collapse in"> <div id="edge-rules" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for r in edge.edge_label.rules.all %} {% for r in edge.edge_label.rules.all %}
<a class="list-group-item" href="{{ r.url }}">{{ r.name|nh_safe }}</a> <a class="list-group-item" href="{{ r.url }}">{{ r.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -133,7 +133,7 @@
<div id="edge-scenario" class="panel-collapse collapse in"> <div id="edge-scenario" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for s in edge.scenarios.all %} {% for s in edge.scenarios.all %}
<a class="list-group-item" href="{{ s.url }}">{{ s.name|nh_safe }} <i>({{ s.package.name|nh_safe }})</i></a> <a class="list-group-item" href="{{ s.url }}">{{ s.name|safe }} <i>({{ s.package.name|safe }})</i></a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -12,7 +12,7 @@
<div class="panel-group" id="package-detail"> <div class="panel-group" id="package-detail">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ group.name|nh_safe }} {{ group.name|safe }}
<div id="actionsButton" <div id="actionsButton"
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;" style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
@ -27,7 +27,7 @@
</div> </div>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p> {{ group.description|nh_safe }} </p> <p> {{ group.description|safe }} </p>
</div> </div>
</div> </div>
@ -40,10 +40,10 @@
</div> </div>
<ul class="list-group"> <ul class="list-group">
{% for um in group.user_member.all %} {% for um in group.user_member.all %}
<a class="list-group-item" href="{{ um.url }}">{{ um.username|nh_safe }}</a> <a class="list-group-item" href="{{ um.url }}">{{ um.username|safe }}</a>
{% endfor %} {% endfor %}
{% for gm in group.group_member.all %} {% for gm in group.group_member.all %}
<a class="list-group-item" href="{{ gm.url }}">{{ gm.name|nh_safe }}</a> <a class="list-group-item" href="{{ gm.url }}">{{ gm.name|safe }}</a>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
@ -57,7 +57,7 @@
</div> </div>
<ul class="list-group"> <ul class="list-group">
{% for p in packages %} {% for p in packages %}
<a class="list-group-item" href="{{ p.url }}">{{ p.name|nh_safe }}</a> <a class="list-group-item" href="{{ p.url }}">{{ p.name|safe }}</a>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>

View File

@ -18,7 +18,7 @@
<div class="panel-group" id="model-detail"> <div class="panel-group" id="model-detail">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ model.name|nh_safe }} {{ model.name|safe }}
<div id="actionsButton" <div id="actionsButton"
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;" style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
@ -33,7 +33,7 @@
</div> </div>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p> {{ model.description|nh_safe }} </p> <p> {{ model.description|safe }} </p>
</div> </div>
{% if model|classname == 'MLRelativeReasoning' or model|classname == 'RuleBasedRelativeReasoning'%} {% if model|classname == 'MLRelativeReasoning' or model|classname == 'RuleBasedRelativeReasoning'%}
<!-- Rule Packages --> <!-- Rule Packages -->
@ -46,7 +46,7 @@
<div id="rule-package" class="panel-collapse collapse in"> <div id="rule-package" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for p in model.rule_packages.all %} {% for p in model.rule_packages.all %}
<a class="list-group-item" href="{{ p.url }}">{{ p.name|nh_safe }}</a> <a class="list-group-item" href="{{ p.url }}">{{ p.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -60,7 +60,7 @@
<div id="reaction-package" class="panel-collapse collapse in"> <div id="reaction-package" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for p in model.data_packages.all %} {% for p in model.data_packages.all %}
<a class="list-group-item" href="{{ p.url }}">{{ p.name|nh_safe }}</a> <a class="list-group-item" href="{{ p.url }}">{{ p.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -75,7 +75,7 @@
<div id="eval-package" class="panel-collapse collapse in"> <div id="eval-package" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for p in model.eval_packages.all %} {% for p in model.eval_packages.all %}
<a class="list-group-item" href="{{ p.url }}">{{ p.name|nh_safe }}</a> <a class="list-group-item" href="{{ p.url }}">{{ p.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -13,7 +13,7 @@
<div class="panel-group" id="node-detail"> <div class="panel-group" id="node-detail">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ node.name|nh_safe }} {{ node.name|safe }}
<div id="actionsButton" <div id="actionsButton"
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;" style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
@ -40,7 +40,7 @@
</div> </div>
<div id="node-desc" class="panel-collapse collapse in"> <div id="node-desc" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{{ node.description|nh_safe }} {{ node.description|safe }}
</div> </div>
</div> </div>
@ -99,7 +99,7 @@
<div id="node-scenario" class="panel-collapse collapse in"> <div id="node-scenario" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for s in node.scenarios.all %} {% for s in node.scenarios.all %}
<a class="list-group-item" href="{{ s.url }}">{{ s.name|nh_safe }} <i>({{ s.package.name|nh_safe }})</i></a> <a class="list-group-item" href="{{ s.url }}">{{ s.name|safe }} <i>({{ s.package.name|safe }})</i></a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -15,7 +15,7 @@
<div class="panel-group" id="package-detail"> <div class="panel-group" id="package-detail">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ package.name|nh_safe }} {{ package.name|safe }}
<div id="actionsButton" <div id="actionsButton"
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;" style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
@ -30,7 +30,7 @@
</div> </div>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p> {{ package.description|nh_safe }} </p> <p> {{ package.description|safe }} </p>
</div> </div>
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item"> <li class="list-group-item">

View File

@ -98,7 +98,7 @@
<div class="panel-group" id="pwAccordion"> <div class="panel-group" id="pwAccordion">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ pathway.name|nh_safe }} {{ pathway.name|safe }}
</div> </div>
</div> </div>
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver"> <div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
@ -208,7 +208,7 @@
</div> </div>
<div id="Description" class="panel-collapse collapse in"> <div id="Description" class="panel-collapse collapse in">
<div class="panel-body list-group-item" id="DescriptionContent"> <div class="panel-body list-group-item" id="DescriptionContent">
{{ pathway.description | nh_safe }} {{ pathway.description | safe }}
</div> </div>
</div> </div>
@ -239,7 +239,7 @@
<div id="pathway-scenario" class="panel-collapse collapse in"> <div id="pathway-scenario" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for s in pathway.scenarios.all %} {% for s in pathway.scenarios.all %}
<a class="list-group-item" href="{{ s.url }}">{{ s.name|nh_safe }} <i>({{ s.package.name|nh_safe }})</i></a> <a class="list-group-item" href="{{ s.url }}">{{ s.name|safe }} <i>({{ s.package.name|safe }})</i></a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -269,7 +269,7 @@
<td colspan="2"> <td colspan="2">
<li class="list-group-item"> <li class="list-group-item">
<a href="{{ pathway.setting.model.url }}"> <a href="{{ pathway.setting.model.url }}">
{{ pathway.setting.model.name|nh_safe }} {{ pathway.setting.model.name|safe }}
</a> </a>
</li> </li>
</td> </td>
@ -302,7 +302,7 @@
{% for p in pathway.setting.rule_packages.all %} {% for p in pathway.setting.rule_packages.all %}
<li class="list-group-item"> <li class="list-group-item">
<a href="{{ p.url }}"> <a href="{{ p.url }}">
{{ p.name|nh_safe }} {{ p.name|safe }}
</a> </a>
</li> </li>
{% endfor %} {% endfor %}

View File

@ -15,7 +15,7 @@
<div class="panel-group" id="reaction-detail"> <div class="panel-group" id="reaction-detail">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ reaction.name|nh_safe }} {{ reaction.name|safe }}
<div id="actionsButton" <div id="actionsButton"
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;" style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
@ -39,7 +39,7 @@
</div> </div>
<div id="reaction-desc" class="panel-collapse collapse in"> <div id="reaction-desc" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{{ reaction.description|nh_safe }} {{ reaction.description|safe }}
</div> </div>
</div> </div>
@ -85,12 +85,12 @@
<div id="reaction-description-smiles" class="panel-collapse collapse in"> <div id="reaction-description-smiles" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for educt in reaction.educts.all %} {% for educt in reaction.educts.all %}
<a class="btn btn-default" href="{{ educt.url }}">{{ educt.name|nh_safe }}</a> <a class="btn btn-default" href="{{ educt.url }}">{{ educt.name|safe }}</a>
{% endfor %} {% endfor %}
<span class="glyphicon glyphicon-arrow-right" style="margin-left:5em;margin-right:5em;" <span class="glyphicon glyphicon-arrow-right" style="margin-left:5em;margin-right:5em;"
aria-hidden="true"></span> aria-hidden="true"></span>
{% for product in reaction.products.all %} {% for product in reaction.products.all %}
<a class="btn btn-default" href="{{ product.url }}">{{ product.name|nh_safe }}</a> <a class="btn btn-default" href="{{ product.url }}">{{ product.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -119,7 +119,7 @@
<div id="reaction-rules" class="panel-collapse collapse in"> <div id="reaction-rules" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for r in reaction.rules.all %} {% for r in reaction.rules.all %}
<a class="list-group-item" href="{{ r.url }}">{{ r.name|nh_safe }}</a> <a class="list-group-item" href="{{ r.url }}">{{ r.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -136,7 +136,7 @@
<div id="reaction-pathway" class="panel-collapse collapse in"> <div id="reaction-pathway" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for r in reaction.related_pathways %} {% for r in reaction.related_pathways %}
<a class="list-group-item" href="{{ r.url }}">{{ r.name|nh_safe }}</a> <a class="list-group-item" href="{{ r.url }}">{{ r.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -152,7 +152,7 @@
<div id="reaction-scenario" class="panel-collapse collapse in"> <div id="reaction-scenario" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for s in reaction.scenarios.all %} {% for s in reaction.scenarios.all %}
<a class="list-group-item" href="{{ s.url }}">{{ s.name|nh_safe }} <i>({{ s.package.name|nh_safe }})</i></a> <a class="list-group-item" href="{{ s.url }}">{{ s.name|safe }} <i>({{ s.package.name|safe }})</i></a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -11,7 +11,7 @@
<div class="panel-group" id="scenario-detail"> <div class="panel-group" id="scenario-detail">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ scenario.name|nh_safe }} {{ scenario.name|safe }}
<div id="actionsButton" <div id="actionsButton"
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;" style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
@ -31,7 +31,7 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading">Description</div> <div class="panel-heading">Description</div>
<div class="panel-body"> <div class="panel-body">
{{ scenario.description|nh_safe }} {{ scenario.description|safe }}
<br> <br>
{{ scenario.scenario_type }} {{ scenario.scenario_type }}
<br> <br>
@ -53,9 +53,9 @@
{% for ai in scenario.get_additional_information %} {% for ai in scenario.get_additional_information %}
<tr> <tr>
<td> {{ ai.property_name|nh_safe }} </td> <td> {{ ai.property_name|safe }} </td>
<td> {{ ai.property_data|nh_safe }} </td> <td> {{ ai.property_data|safe }} </td>
<td> {{ ai.property_unit|nh_safe }} </td> <td> {{ ai.property_unit|safe }} </td>
{% if meta.can_edit %} {% if meta.can_edit %}
<td> <td>
<form action="{% url 'package scenario detail' scenario.package.uuid scenario.uuid %}" method="post"> <form action="{% url 'package scenario detail' scenario.package.uuid scenario.uuid %}" method="post">

View File

@ -14,7 +14,7 @@
<div class="panel-group" id="rule-detail"> <div class="panel-group" id="rule-detail">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px"> <div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
{{ rule.name|nh_safe }} {{ rule.name|safe }}
<div id="actionsButton" <div id="actionsButton"
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;" style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
@ -30,7 +30,7 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p> <p>
{{ rule.description|nh_safe }} {{ rule.description|safe }}
</p> </p>
</div> </div>
@ -146,7 +146,7 @@
<div id="rule-composite-rule" class="panel-collapse collapse in"> <div id="rule-composite-rule" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for cr in rule.parallelrule_set.all %} {% for cr in rule.parallelrule_set.all %}
<a class="list-group-item" href="{{ cr.url }}">{{ cr.name|nh_safe }}</a> <a class="list-group-item" href="{{ cr.url }}">{{ cr.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -163,7 +163,7 @@
<div id="rule-scenario" class="panel-collapse collapse in"> <div id="rule-scenario" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for s in rule.scenarios.all %} {% for s in rule.scenarios.all %}
<a class="list-group-item" href="{{ s.url }}">{{ s.name|nh_safe }}</a> <a class="list-group-item" href="{{ s.url }}">{{ s.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -180,7 +180,7 @@
<div id="rule-reaction" class="panel-collapse collapse"> <div id="rule-reaction" class="panel-collapse collapse">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for r in rule.related_reactions %} {% for r in rule.related_reactions %}
<a class="list-group-item" href="{{ r.url }}">{{ r.name|nh_safe }}</a> <a class="list-group-item" href="{{ r.url }}">{{ r.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
@ -197,7 +197,7 @@
<div id="rule-pathway" class="panel-collapse collapse"> <div id="rule-pathway" class="panel-collapse collapse">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for r in rule.related_pathways %} {% for r in rule.related_pathways %}
<a class="list-group-item" href="{{ r.url }}">{{ r.name|nh_safe }}</a> <a class="list-group-item" href="{{ r.url }}">{{ r.name|safe }}</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -42,7 +42,7 @@
<div id="default-package" class="panel-collapse collapse in"> <div id="default-package" class="panel-collapse collapse in">
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
<li class="list-group-item"> <li class="list-group-item">
<a href="{{ user.default_package.url }}"> {{ user.default_package.name|nh_safe }}</a> <a href="{{ user.default_package.url }}"> {{ user.default_package.name|safe }}</a>
</li> </li>
</div> </div>
</div> </div>
@ -59,7 +59,7 @@
<div class="panel-body list-group-item"> <div class="panel-body list-group-item">
{% for g in meta.available_groups %} {% for g in meta.available_groups %}
<li class="list-group-item"> <li class="list-group-item">
<a href="{{ g.url }}"> {{ g.name|nh_safe }}</a> <a href="{{ g.url }}"> {{ g.name|safe }}</a>
</li> </li>
{% endfor %} {% endfor %}
</div> </div>
@ -91,7 +91,7 @@
<td colspan="2"> <td colspan="2">
<li class="list-group-item"> <li class="list-group-item">
<a href="{{user.default_setting.model.url}}"> <a href="{{user.default_setting.model.url}}">
{{ user.default_setting.model.name|nh_safe }} {{ user.default_setting.model.name|safe }}
</a> </a>
</li> </li>
</td> </td>
@ -124,7 +124,7 @@
{% for p in user.default_setting.rule_packages.all %} {% for p in user.default_setting.rule_packages.all %}
<li class="list-group-item"> <li class="list-group-item">
<a href="{{p.url}}"> <a href="{{p.url}}">
{{ p.name|nh_safe }} {{ p.name|safe }}
</a> </a>
</li> </li>
{% endfor %} {% endfor %}

View File

@ -19,7 +19,7 @@
</head> </head>
<body> <body>
<p></p> <p></p>
{{ pathway.name|nh_safe }} {{ pathway.name|safe }}
<div id="viz"> <div id="viz">
<svg width="2000" height="2000"> <!-- Sehr großes SVG für Zoom --> <svg width="2000" height="2000"> <!-- Sehr großes SVG für Zoom -->
<defs> <defs>

View File

@ -12,13 +12,13 @@
<option disabled>Reviewed Packages</option> <option disabled>Reviewed Packages</option>
{% endif %} {% endif %}
{% for obj in reviewed_objects %} {% for obj in reviewed_objects %}
<option value="{{ obj.url }}" selected>{{ obj.name|nh_safe }}</option> <option value="{{ obj.url }}" selected>{{ obj.name|safe }}</option>
{% endfor %} {% endfor %}
{% if unreviewed_objects %} {% if unreviewed_objects %}
<option disabled>Unreviewed Packages</option> <option disabled>Unreviewed Packages</option>
{% endif %} {% endif %}
{% for obj in unreviewed_objects %} {% for obj in unreviewed_objects %}
<option value="{{ obj.url }}">{{ obj.name|nh_safe }}</option> <option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>