diff --git a/snpdb/models/models.py b/snpdb/models/models.py
index 925cd8171..aa026b244 100644
--- a/snpdb/models/models.py
+++ b/snpdb/models/models.py
@@ -22,7 +22,7 @@
from django.conf import settings
from django.contrib.auth.models import User, Group
from django.core.cache import cache
-from django.core.exceptions import PermissionDenied, ValidationError
+from django.core.exceptions import FieldDoesNotExist, PermissionDenied, ValidationError
from django.db import models
from django.db.models import QuerySet, TextChoices
from django.db.models.deletion import SET_NULL, CASCADE, PROTECT
@@ -206,6 +206,10 @@ def get_subclass_by_name(class_name):
@staticmethod
def get_or_create(class_name, unique_keyword, unique_value):
klass = Wiki.get_subclass_by_name(class_name)
+ try:
+ klass._meta.get_field(unique_keyword)
+ except FieldDoesNotExist:
+ raise PermissionDenied(f"'{unique_keyword}' is not a valid field for {class_name}")
wiki, _ = klass.objects.get_or_create(**{unique_keyword: unique_value})
return wiki
diff --git a/snpdb/templatetags/model_tags.py b/snpdb/templatetags/model_tags.py
index 86a88b104..58348f2e5 100644
--- a/snpdb/templatetags/model_tags.py
+++ b/snpdb/templatetags/model_tags.py
@@ -1,4 +1,5 @@
from django.template.library import Library
+from django.utils.html import escape
from django.utils.safestring import mark_safe
from snpdb.models import Trio, Quad
@@ -18,5 +19,5 @@ def quad_table(quad: Quad):
@register.simple_tag
def trio_short_description(trio: Trio):
- params = (trio.mother_details, trio.father_details, trio.proband)
+ params = (escape(trio.mother_details), escape(trio.father_details), escape(trio.proband))
return mark_safe("M: %s/F: %s/P: %s" % params)
diff --git a/snpdb/views/views.py b/snpdb/views/views.py
index bcde1a434..efcdd0fdd 100644
--- a/snpdb/views/views.py
+++ b/snpdb/views/views.py
@@ -13,6 +13,7 @@
from django.core.exceptions import PermissionDenied, ImproperlyConfigured, ObjectDoesNotExist
from django.db.utils import IntegrityError
from django.forms.models import inlineformset_factory, ALL_FIELDS
+from django.utils.html import escape
from django.forms.widgets import TextInput
from django.http import HttpRequest
from django.http.response import HttpResponse, HttpResponseRedirect, HttpResponseServerError, JsonResponse
@@ -1353,11 +1354,11 @@ def sample_gene_matrix(request, variant_annotation_version, samples, gene_list,
sample_code = "%03d" % i
if can_access:
view_sample_url = reverse('view_sample', kwargs={'sample_id': sample.pk})
-
- sample_link = f'{sample.name}'
+ safe_name = escape(sample.name)
+ sample_link = f'{safe_name}'
if sample_link in used_sample_names:
- uniq_sample_name = sample.name + "_" + sample_code
- sample_link = f'{uniq_sample_name}'
+ safe_uniq_name = escape(sample.name + "_" + sample_code)
+ sample_link = f'{safe_uniq_name}'
sample_name = sample_link
else: