numerous updates to case collections

This commit is contained in:
Ross
2024-02-12 13:05:26 +00:00
parent c3f7913402
commit b9cdbb98ef
10 changed files with 158 additions and 29 deletions
@@ -0,0 +1,18 @@
# Generated by Django 4.1.4 on 2024-02-12 12:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('atlas', '0037_alter_seriesimage_image_blake3_hash'),
]
operations = [
migrations.AddField(
model_name='casecollection',
name='viewer_mode',
field=models.CharField(choices=[('BUILT_IN', 'Built in viewer'), ('OHIF', 'OHIF Viewer'), ('BUILT_IN_WITH_OHIF', 'Built in viewer with OHIF Viewer option')], default='BUILT_IN', max_length=100),
),
]
+50 -3
View File
@@ -699,6 +699,26 @@ class CaseCollection(ExamOrCollectionGenericBase):
default=COLLECTION_TYPE_CHOICES.REPORT,
)
class VIEWER_MODE_CHOICES(models.TextChoices):
BUILT_IN = (
"BUILT_IN",
_("Built in viewer"),
)
OHIF = (
"OHIF",
_("OHIF Viewer"),
)
BUILT_IN_WITH_OHIF = (
"BUILT_IN_WITH_OHIF",
_("Built in viewer with OHIF Viewer option"),
)
viewer_mode = models.CharField(
max_length=100,
choices=VIEWER_MODE_CHOICES.choices,
default=VIEWER_MODE_CHOICES.BUILT_IN,
)
def get_absolute_url(self):
return reverse("atlas:collection_detail", kwargs={"pk": self.pk})
@@ -708,6 +728,18 @@ class CaseCollection(ExamOrCollectionGenericBase):
def __str__(self) -> str:
return self.name
def show_built_in_viewer(self) -> bool:
return self.viewer_mode in (
self.VIEWER_MODE_CHOICES.BUILT_IN,
self.VIEWER_MODE_CHOICES.BUILT_IN_WITH_OHIF,
)
def show_ohif_viewer_link(self) -> bool:
return self.viewer_mode in (
self.VIEWER_MODE_CHOICES.OHIF,
self.VIEWER_MODE_CHOICES.BUILT_IN_WITH_OHIF,
)
def review_only(self) -> bool:
"""Returns True if a users cannot submit responses
@@ -719,6 +751,17 @@ class CaseCollection(ExamOrCollectionGenericBase):
return False
def in_review_mode(self) -> bool:
return self.review_only() or self.publish_results
# def can_answer(self) -> bool:
# """Returns true if the user is able to answer questions in a collection
# (independent of current collection state (e.g. published / not published))"""
# if self.collection_type == self.COLLECTION_TYPE_CHOICES.REPORT:
# return True
# return False
def get_case_by_index(
self, case_index: int, case_count=False
) -> Case | Tuple[Case, int]:
@@ -892,8 +935,10 @@ class UncategorisedDicom(models.Model):
def check_for_duplicates(self, image_hash):
duplicate = None
if obj := UncategorisedDicom.objects.filter(image_blake3_hash=image_hash).first():
#duplicate = obj
if obj := UncategorisedDicom.objects.filter(
image_blake3_hash=image_hash
).first():
# duplicate = obj
return obj
print(image_hash)
@@ -912,7 +957,9 @@ class UncategorisedDicom(models.Model):
# if self.check_for_duplicates():
# return DuplicateDicom
image_blake3_hash = get_image_dicom_hash(None, dataset=ds, hash_type="blake3", direct_pixel_data=True)
image_blake3_hash = get_image_dicom_hash(
None, dataset=ds, hash_type="blake3", direct_pixel_data=True
)
self.image_blake3_hash = image_blake3_hash
@@ -0,0 +1,13 @@
<span id="add-case-form">
<form hx-post="{% url 'atlas:add_case_to_collection' collection.id %}" hx-swap="outerHTML">
{% csrf_token %}
<label for="case">Select Case:</label>
<select name="case" id="case">
{% for case in cases %}
<option value="{{ case.id }}">{{ case.title }}</option>
{% endfor %}
</select>
<button type="submit">Add</button>
<button _="on click remove #add-case-form">Cancel</button>
</form>
</span
+1 -1
View File
@@ -53,7 +53,7 @@
Use this form to create a atlas case. Existing associated image sets can be added using this form.
{% if form.collection %}
<div class="alert alert-info" role="alert">Creating a case in the collection: <a href="{% url 'atlas:collection_detail' pk=form.exam.pk %}">{{form.collection.name}}</a></div>
<div class="alert alert-info" role="alert">Creating a case in the collection: <a href="{% url 'atlas:collection_detail' pk=form.collection.pk %}">{{form.collection.name}}</a></div>
{% endif %}
<form action="" method="post" enctype="multipart/form-data" id="atlas-form">
{% csrf_token %}
@@ -28,29 +28,42 @@
</div>
{% endif %}
<div class="pre-whitespace multi-image-block">
<details open>
<summary>
Images
</summary>
{% for series in series_list %}
<span class="series-block">
<a href="#" onclick='window.loadDicomViewer(window.images[{{forloop.counter0}}])'>
<span>
<span class="series-block-series-number">Series {{ forloop.counter }}:</span>
{{series.get_block}}
</span>
</a>
</span>
{% endfor %}
</details>
</div>
<div>
<div id="single-dicom-viewer" class="dicom-viewer" data-images="" data-annotations=''>
{% if collection.show_ohif_viewer_link %}
<div>
<a href="https://viewer.penracourses.org.uk/viewer/dicomjson?url=https://www.penracourses.org.uk{% url 'atlas:case_dicom_json' case.pk %}">View case in OHIF</a>
</div>
{% endif %}
{% if collection.show_built_in_viewer %}
<div class="pre-whitespace multi-image-block">
<details open>
<summary>
Images
</summary>
{% for series in series_list %}
<span class="series-block">
<a href="#" onclick='window.loadDicomViewer(window.images[{{forloop.counter0}}])'>
<span>
<span class="series-block-series-number">Series {{ forloop.counter }}:</span>
{{series.get_block}}
</span>
</a>
</span>
{% endfor %}
</details>
</div>
</div>
<div>
<div id="single-dicom-viewer" class="dicom-viewer" data-images="" data-annotations=''>
</div>
</div>
{% else %}
{% endif %}
{% if show_discussion and case.discussion %}
<p>
<details>
+7 -1
View File
@@ -21,8 +21,14 @@
<p>This collection will be available to view/take <a href='{{collection.get_take_url}}'>here</a>
{% if can_edit %}
<p><button id='button-edit-order' title='click and drag questions to change order' data-posturl="{% url 'atlas:exam_json_edit' pk=collection.pk %}">Edit case order / Delete cases</button></p>
<p><button id='button-add-case'
title='click to add a case to this collection'
hx-get="{% url 'atlas:add_case_to_collection' collection.pk %}" hx-swap="innerHTML" hx-target="#case-list">
Add case
</button>
<div id='case-list'></div>
</p>
{% endif %}
{% include 'exam_overview_js.html' %}
{% endblock %}
@@ -7,12 +7,15 @@
<h2>Collection: {{collection.name}}
{% if collection.publish_results or cid_user_exam.completed %}
{% if collection.in_review_mode or cid_user_exam.completed %}
<span class="stamp-white">REVIEW</span>
{% endif %}
</h2>
{{answer_count}} out of {{collection_length}} cases answered. Click to go to case.
{% if not collection.review_only %}
{{answer_count}} out of {{collection_length}} cases answered. Click to go to case.
{% endif %}
<div class="sba-finish-list">
<ul>
{% for question, answer, self_review in question_answer_tuples %}
@@ -40,9 +43,8 @@
</ul>
</div>
Start time: {{cid_user_exam.start_time}}
{% if collection.self_review %}
<p>Completed: <span id="completed-state">{{cid_user_exam.completed}}</span></p>
@@ -3,6 +3,8 @@
{% block content %}
<h2>Collections</h2>
The following collections are available for you to view / take.
<ul>
{% for collection in collections %}
+1
View File
@@ -32,6 +32,7 @@ urlpatterns = [
path("author/<int:pk>/", views.author_detail, name="author_detail"),
path("author/", views.author_list, name="author_list"),
path("case/", views.CaseView.as_view(), name="case_view"),
path("collection/<int:collection_id>/add_case", views.add_case_to_collection, name="add_case_to_collection"),
path("collection/", views.CollectionView.as_view(), name="collection_view"),
path("collection/user", views.user_collections, name="user_collections"),
path("uploads", views.user_uploads, name="user_uploads"),
+27
View File
@@ -136,6 +136,14 @@ import difflib
logger = logging.getLogger(__name__)
def get_cases_available_to_user(user):
"""Returns a queryset of cases available to the user"""
return Case.objects.filter(author=user) | Case.objects.filter(open_access=True)
if user.is_superuser:
return Case.objects.all()
else:
return Case.objects.filter(author=user) | Case.objects.filter(open_access=True)
class AuthorOrCheckerRequiredMixin(object):
def get_object(self, *args, **kwargs):
@@ -370,6 +378,25 @@ def user_collections(request):
return render(request, "atlas/user_collections.html", {"collections": collections})
def add_case_to_collection(request, collection_id):
if not request.htmx:
return Http404
collection = get_object_or_404(CaseCollection, pk=collection_id)
if request.method == "POST":
case = get_object_or_404(Case, pk=request.POST["case"])
print(case)
collection.cases.add(case)
return HttpResponse("Case added to collection")
#if request.method == "POST":
cases = get_cases_available_to_user(request.user)
return render(request, "atlas/add_case_to_collection.html", {"cases": cases, "collection": collection})
@login_required
def user_uploads_series(request, series_instance_uid: str):