numerous updates to case collections
This commit is contained in:
@@ -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
@@ -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
|
||||
@@ -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>
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user