fix a few things

This commit is contained in:
Ross
2023-06-12 16:16:45 +01:00
parent d1ba8c87dc
commit 5fbd4cd35e
6 changed files with 57 additions and 72 deletions
-48
View File
@@ -502,54 +502,6 @@ class CaseCollection(ExamCollectionGenericBase):
def __str__(self) -> str: def __str__(self) -> str:
return self.name return self.name
def get_author_objects(self):
"""Returns a comma seperated text list of authors"""
authors = [i for i in self.author.all()]
return authors
def check_cid_user(self, cid, passcode, request=None):
if request is not None and request.user.is_superuser:
return True
if self.valid_cid_users.exists():
user = self.valid_cid_users.filter(cid=cid).first()
if not user or user.passcode != passcode:
return False
return True
def get_or_create_cid_user_exam(self, cid_user, start_time=None):
content_type = ContentType.objects.get_for_model(self)
c = CidUserExam.objects.filter(
content_type=content_type, object_id=self.pk, cid_user=cid_user
).first()
if c:
return c
if start_time is None:
start_time = timezone.now()
new = CidUserExam(
content_type=content_type,
object_id=self.pk,
cid_user=cid_user,
start_time=start_time,
)
new.save()
return new
def get_cid_user_exams(self, cid_user=None):
content_type = ContentType.objects.get_for_model(self)
if cid_user is None:
return CidUserExam.objects.filter(
content_type=content_type,
object_id=self.pk,
)
else:
return CidUserExam.objects.filter(
content_type=content_type, object_id=self.pk, cid_user=cid_user
)
class CaseDetail(models.Model): class CaseDetail(models.Model):
case = models.ForeignKey(Case, on_delete=models.CASCADE) case = models.ForeignKey(Case, on_delete=models.CASCADE)
@@ -28,13 +28,15 @@
{% for series in case.series.all %} {% for series in case.series.all %}
<span class="series-block"> <span class="series-block">
<span> <span>
<span class="series-block-series-number">Series {{ forloop.counter }}:</span> <span class="series-block-series-number">Series {{ forloop.counter }}:</span><br>
<a href="{% url 'atlas:series_detail' pk=series.pk %}"> <a href="{% url 'atlas:series_detail' pk=series.pk %}">
{{series.get_block}} {{series.get_block}}
</a> </a>
<br>
<span class="series-block-popup-link">
<a href="#" <a href="#"
onclick="return window.create_popup_window('/atlas/series/{{series.pk}}', 'Series')">Popup</a> onclick="return window.create_popup_window('/atlas/series/{{series.pk}}', 'Series')">Popup</a>
</span>
</span> </span>
</span> </span>
{% endfor %} {% endfor %}
+16 -10
View File
@@ -39,7 +39,7 @@
{% for finding in series.findings.all %} {% for finding in series.findings.all %}
<div class="finding-box"> <div class="finding-box">
<button class="view-finding-button" data-annotationjson={{finding.annotation_json}} <button class="view-finding-button" data-annotationjson={{finding.annotation_json}}
data-viewportjson={{finding.viewport_json}} data-findingid={{finding.id}}>Click to view</button> data-viewportjson={{finding.viewport_json}} data-findingid={{finding.id}}>Click to view</button>
<span class="view-finding-details"> <span class="view-finding-details">
Finding(s): {% for f in finding.findings.all %}{{f.get_link}}{% endfor %}<br /> Finding(s): {% for f in finding.findings.all %}{{f.get_link}}{% endfor %}<br />
Structure(s): {% for s in finding.structures.all %}{{s.get_link}}{% endfor %}<br /> Structure(s): {% for s in finding.structures.all %}{{s.get_link}}{% endfor %}<br />
@@ -58,18 +58,24 @@
<summary>Image info</summary> <summary>Image info</summary>
<div> <div>
<a href="{% url 'atlas:series_anonymise_dicom' pk=series.pk %}" <a href="{% url 'atlas:series_anonymise_dicom' pk=series.pk %}"
title="Anonymise dicom images">Anonymise dicoms</a><br /> title="Anonymise dicom images">Anonymise dicoms</a><br />
<a href="{% url 'atlas:series_order_dicom' pk=series.pk %}" title="orders dicom by slice location">Order dicoms <a href="{% url 'atlas:series_order_dicom' pk=series.pk %}" title="orders dicom by slice location">Order dicoms
by slice location</a> by slice location</a>
<a href="{% url 'atlas:series_order_dicom_instance' pk=series.pk %}" <a href="{% url 'atlas:series_order_dicom_instance' pk=series.pk %}"
title="orders dicom by instance number">Order dicoms by instance number</a> title="orders dicom by instance number">Order dicoms by instance number</a>
<a href="{% url 'atlas:series_order_dicom_SeriesInstanceUID' pk=series.pk %}" <a href="{% url 'atlas:series_order_dicom_SeriesInstanceUID' pk=series.pk %}"
title="orders dicom by instance number">Order dicoms by SeriesInstanceUID</a> title="orders dicom by instance number">Order dicoms by SeriesInstanceUID</a>
<a href="{% url 'atlas:series_order_upload_filename' pk=series.pk %}" <a href="{% url 'atlas:series_order_upload_filename' pk=series.pk %}"
title="orders dicom by uploaded filename">Order by uploaded filename</a> title="orders dicom by uploaded filename">Order by uploaded filename</a>
</div> </div>
{% for image in series.images.all %} {% for image in series.images.all %}
{{image.image.url}}, pos: {{image.position}}, {{image.upload_filename}} [{{image.image.size|filesizeformat}}]<br /> {{image.image.url}}, pos: {{image.position}}, {{image.upload_filename}}
{% if image.image %}
[{{image.image.size|filesizeformat}}]
{% endif %}
<br />
{% comment %} {{image.get_dicom_info|safe}}<br /> {% endcomment %} {% comment %} {{image.get_dicom_info|safe}}<br /> {% endcomment %}
{% endfor %} {% endfor %}
@@ -159,13 +165,13 @@
viewport_json: JSON.stringify(c.viewport), viewport_json: JSON.stringify(c.viewport),
findings: JSON.stringify($('#finding-form select[name="findings"]').find(":selected") findings: JSON.stringify($('#finding-form select[name="findings"]').find(":selected")
.map((i, el) => { .map((i, el) => {
return $(el).val() return $(el).val()
}).toArray()), }).toArray()),
structures: JSON.stringify($('#finding-form select[name="structures"]').find( structures: JSON.stringify($('#finding-form select[name="structures"]').find(
":selected") ":selected")
.map((i, el) => { .map((i, el) => {
return $(el).val() return $(el).val()
}).toArray()), }).toArray()),
csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(), csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),
action: 'post' action: 'post'
}, },
+19 -8
View File
@@ -116,6 +116,7 @@ class QuestionBase(models.Model):
"""If this makes sense in the question/answer context override""" """If this makes sense in the question/answer context override"""
return None return None
class SeriesImageBase(models.Model): class SeriesImageBase(models.Model):
position = models.IntegerField(default=0) position = models.IntegerField(default=0)
upload_filename = models.CharField(max_length=255, blank=True) upload_filename = models.CharField(max_length=255, blank=True)
@@ -206,9 +207,9 @@ class SeriesBase(models.Model):
thumbnailer = get_thumbnailer(img) thumbnailer = get_thumbnailer(img)
thumbnail = thumbnailer["exam-list"] thumbnail = thumbnailer["exam-list"]
except InvalidImageFormatError: except InvalidImageFormatError:
return format_html('<img title="{}" src="/static/not-found-image.jpg" />', img), len( return format_html(
images '<img title="{}" src="/static/not-found-image.jpg" />', img
) ), len(images)
return format_html('<img src="/media/{}" />', thumbnail), len(images) return format_html('<img src="/media/{}" />', thumbnail), len(images)
def get_thumbnail_link(self): def get_thumbnail_link(self):
@@ -216,21 +217,30 @@ class SeriesBase(models.Model):
"<a href='{}'>{}<a/>", self.get_absolute_url(), self.get_thumbnail()[0] "<a href='{}'>{}<a/>", self.get_absolute_url(), self.get_thumbnail()[0]
) )
def get_block(self): def get_block(self, series_number: None | int = None):
examination = self.get_examination_full() examination = self.get_examination_full()
thumb, image_number = self.get_thumbnail() thumb, image_number = self.get_thumbnail()
series_html = ""
if series_number is not None:
series_html = format_html(
"<span class='series-block-series-number'>Series {}</span><br>",
series_number,
)
return format_html( return format_html(
"""<span> """{}
<span>
<span class='series-block-examination'>{}</span><br/> <span class='series-block-examination'>{}</span><br/>
<span class='series-block-thumbnail'>{}</span><br/> <span class='series-block-thumbnail'>{}</span><br/>
<span class='series-block-image-number'>Images: <span class='series-block-image-number-count'>{}</span></span> <span class='series-block-image-number'>Images: <span class='series-block-image-number-count'>{}</span></span>
</span>""", </span>""",
series_html,
examination, examination,
thumb, thumb,
image_number, image_number,
) )
def order_by_upload_filename(self): def order_by_upload_filename(self):
images = self.images.all() images = self.images.all()
@@ -311,12 +321,14 @@ class SeriesBase(models.Model):
except pydicom.errors.InvalidDicomError: except pydicom.errors.InvalidDicomError:
pass pass
class ExamCollectionGenericBase(models.Model): class ExamCollectionGenericBase(models.Model):
"""Holds functions that relate to both case and other exams """Holds functions that relate to both case and other exams
e.g. user management e.g. user management
""" """
# Is this actually used? # Is this actually used?
cid_users = GenericRelation("generic.CidUserExam") cid_users = GenericRelation("generic.CidUserExam")
@@ -429,6 +441,7 @@ class ExamCollectionGenericBase(models.Model):
content_type=content_type, object_id=self.pk, user_user=user_user content_type=content_type, object_id=self.pk, user_user=user_user
) )
class ExamBase(ExamCollectionGenericBase): class ExamBase(ExamCollectionGenericBase):
name = models.CharField(max_length=200, help_text="Name of the exam") name = models.CharField(max_length=200, help_text="Name of the exam")
# exam_questions = SortedManyToManyField(Long, related_name="exams", blank="true") # exam_questions = SortedManyToManyField(Long, related_name="exams", blank="true")
@@ -490,7 +503,6 @@ class ExamBase(ExamCollectionGenericBase):
user_scores = models.JSONField(default=dict) user_scores = models.JSONField(default=dict)
exam_results_emailed = models.DateTimeField(default=None, null=True) exam_results_emailed = models.DateTimeField(default=None, null=True)
class Meta: class Meta:
@@ -547,7 +559,6 @@ class ExamBase(ExamCollectionGenericBase):
def get_question_index(self, question): def get_question_index(self, question):
return list(self.exam_questions.all()).index(question) return list(self.exam_questions.all()).index(question)
def get_cid_user_score(self, cid_user): def get_cid_user_score(self, cid_user):
c = "c/" + str(cid_user) c = "c/" + str(cid_user)
if c in self.user_scores: if c in self.user_scores:
+3 -2
View File
@@ -87,6 +87,7 @@ from django.db.models import Case, When
from django.conf import settings from django.conf import settings
from datetime import datetime from datetime import datetime
from django.utils import timezone
import os import os
import string import string
import random import random
@@ -1626,7 +1627,7 @@ class ExamViews(View, LoginRequiredMixin):
return redirect(url) return redirect(url)
return JsonResponse(exam_json_cache) return JsonResponse(exam_json_cache)
time = datetime.now() time = timezone.now()
exam.exam_json_id += 1 exam.exam_json_id += 1
@@ -1672,7 +1673,7 @@ class ExamViews(View, LoginRequiredMixin):
if not exam.check_cid_user(cid, passcode, request, user_id): if not exam.check_cid_user(cid, passcode, request, user_id):
raise Http404("No available exam") raise Http404("No available exam")
time = datetime.now() time = timezone.now()
exam_json = exam.get_exam_json(based=False) exam_json = exam.get_exam_json(based=False)
exam_json["generated"] = time.isoformat() exam_json["generated"] = time.isoformat()
+15 -2
View File
@@ -571,12 +571,21 @@ td.user-answer-score-2.rapid-ans::after {
font-size: small; font-size: small;
} }
.series-block a {
text-decoration: none;
color: unset;
}
.series-block-image-number-count { .series-block-image-number-count {
text-decoration: underline; text-decoration: underline;
} }
.series-block-popup-link { .series-block-popup-link {
font-size: small; font-size: smaller;
color: darkblue }
.series-block-popup-link a {
color: rgb(0, 153, 255);
opacity: 50%;
} }
.series-block img { .series-block img {
@@ -820,6 +829,10 @@ input {
border-radius: 0px; border-radius: 0px;
} }
.select2-results__option {
background-color: #05668d;
}
.select2-search__field { .select2-search__field {
background-color: #05668d; background-color: #05668d;
color: darkblue; color: darkblue;