improve case management
This commit is contained in:
@@ -533,6 +533,15 @@ class Case(models.Model, AuthorMixin, QuestionMixin):
|
||||
|
||||
return size
|
||||
|
||||
def check_user_can_edit(self, user):
|
||||
if user.is_superuser:
|
||||
return True
|
||||
|
||||
if self.author.filter(id=user.id).exists():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -248,14 +248,29 @@
|
||||
</ul>
|
||||
<b>Diagnostic certainty:</b> {{case.get_diagnostic_certainty_display}}<br />
|
||||
<b>Collections:</b>
|
||||
|
||||
{% if can_edit %}
|
||||
<button
|
||||
hx-get="{% url 'atlas:case_collection_form' case.pk %}"
|
||||
hx-target="#collection-form">
|
||||
Add collection</button>
|
||||
{% endif %}
|
||||
<div id="collection-form"></div>
|
||||
<ul>
|
||||
{% for collection in case.casecollection_set.all %}
|
||||
<li><a href="{% url 'atlas:collection_detail' pk=collection.pk %}">{{collection.name}}</a></li>
|
||||
<li id="collection-{{ collection.pk }}">
|
||||
<a href="{% url 'atlas:collection_detail' pk=collection.pk %}">{{ collection.name }}</a>
|
||||
{% if can_edit %}
|
||||
<button
|
||||
class="btn btn-danger btn-sm remove-button"
|
||||
hx-post="{% url 'atlas:remove_case_from_collection' case.pk collection.pk %}"
|
||||
hx-target="#collection-{{ collection.pk }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-confirm="Are you sure you want to remove this case from the collection?">
|
||||
Remove
|
||||
</button>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
<div>
|
||||
{% if collection.self_review %}
|
||||
<p>
|
||||
<a href="{% url 'atlas:add_self_review' cid_user_exam.id case.id %}"><button>Add self review</button></a>
|
||||
<a target="_blank" title="Add self review, this will open in a new page / tab" href="{% url 'atlas:add_self_review' cid_user_exam.id case.id %}"><button type="button">Add self review</button></a>
|
||||
</p>
|
||||
{% if self_review %}
|
||||
<h4>Self Feedback</h4>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
Adding self feedback for {{user_exam.exam}}/{{case}}
|
||||
|
||||
</div>
|
||||
This form allows you to record your own feedback for the question / case. This can take the form of a note or a ranking (1-5) of your findings and interpretation.
|
||||
<form class="highlight" action="" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors }}
|
||||
|
||||
@@ -249,6 +249,11 @@ urlpatterns = [
|
||||
views.use_dates_as_descriptions,
|
||||
name="use_dates_as_descriptions",
|
||||
),
|
||||
path(
|
||||
"case/<int:case_pk>/collection/<int:collection_pk>/remove/",
|
||||
views.remove_case_from_collection,
|
||||
name="remove_case_from_collection",
|
||||
),
|
||||
path(
|
||||
"series/<int:pk>/dicom_json",
|
||||
views.series_dicom_json,
|
||||
|
||||
+43
-10
@@ -7,6 +7,7 @@ from django.db.models.query import QuerySet
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from django import forms
|
||||
from django.utils import timezone
|
||||
from django.views.decorators.http import require_POST
|
||||
|
||||
# from django.contrib.auth.models import User
|
||||
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||
@@ -122,7 +123,7 @@ from .tasks import push_case_to_cimar_task
|
||||
from django_tables2 import SingleTableView, SingleTableMixin
|
||||
from django_filters.views import FilterView
|
||||
|
||||
#from autocomplete import HTMXAutoComplete
|
||||
# from autocomplete import HTMXAutoComplete
|
||||
|
||||
|
||||
from .decorators import (
|
||||
@@ -200,14 +201,26 @@ def case_detail(request, pk):
|
||||
# if request.user not in atlas.author.all():
|
||||
# raise PermissionDenied
|
||||
|
||||
can_edit = case.check_user_can_edit(request.user)
|
||||
|
||||
# logging.debug(atlas.subspecialty.first().name.all())
|
||||
return render(request, "atlas/case_detail.html", {"case": case, "cimar_sid":request.user.userprofile.cimar_sid})
|
||||
return render(
|
||||
request,
|
||||
"atlas/case_detail.html",
|
||||
{
|
||||
"case": case,
|
||||
"cimar_sid": request.user.userprofile.cimar_sid,
|
||||
"can_edit": can_edit,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@user_is_author_or_atlas_series_checker_or_atlas_marker_or_open_access
|
||||
def series_thumbnail_fail(request, pk):
|
||||
return series_thumbnail(request, pk=pk, fail_loudly=True)
|
||||
|
||||
|
||||
@login_required
|
||||
@user_is_author_or_atlas_series_checker_or_atlas_marker_or_open_access
|
||||
def series_thumbnail(request, pk, fail_loudly=False):
|
||||
@@ -962,7 +975,7 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin):
|
||||
form.instance.author.add(self.request.user.id)
|
||||
|
||||
# Check Cimar Case
|
||||
#CimarAPI().get_study_by_uuid(self.object.cimar_uuid)
|
||||
# CimarAPI().get_study_by_uuid(self.object.cimar_uuid)
|
||||
|
||||
context = self.get_context_data(form=form)
|
||||
series_formset = context["series_formset"]
|
||||
@@ -1128,6 +1141,7 @@ def add_collection_to_case_form(request, case_id):
|
||||
# pk = self.kwargs["pk"]
|
||||
# return reverse("atlas:case_detail", kwargs={"pk": pk})
|
||||
|
||||
|
||||
class AtlasClone(AtlasCreateBase, AuthorOrCheckerRequiredMixin, CreateView):
|
||||
"""Clones a existing atlas"""
|
||||
|
||||
@@ -1153,8 +1167,10 @@ class AtlasClone(AtlasCreateBase, AuthorOrCheckerRequiredMixin, CreateView):
|
||||
initial_data = model_to_dict(old_object, exclude=["id", "previous_case"])
|
||||
return initial_data
|
||||
|
||||
|
||||
class AtlasCloneNext(AtlasClone):
|
||||
"""Extends AtlasClone to set the previous_case field to the case being cloned"""
|
||||
|
||||
def get_initial(self):
|
||||
initial_data = super().get_initial()
|
||||
initial_data["previous_case"] = self.kwargs["pk"]
|
||||
@@ -1673,7 +1689,9 @@ def collection_history_user(request, exam_id: int, user_pk: int):
|
||||
print(user)
|
||||
print(casedetails)
|
||||
|
||||
user_answers = [(casedetail, casedetail.get_user_answers(user)) for casedetail in casedetails]
|
||||
user_answers = [
|
||||
(casedetail, casedetail.get_user_answers(user)) for casedetail in casedetails
|
||||
]
|
||||
|
||||
return render(
|
||||
request,
|
||||
@@ -1701,7 +1719,6 @@ def collection_take_start(request, pk):
|
||||
|
||||
valid_user = collection.check_logged_in_user(request)
|
||||
|
||||
|
||||
# for now we only allow registered users....
|
||||
if not valid_user:
|
||||
raise PermissionDenied
|
||||
@@ -2399,7 +2416,7 @@ def collection_case_view(request, pk, case_number):
|
||||
"previous": previous,
|
||||
"next": next,
|
||||
"answer": answer,
|
||||
"cimar_sid":request.user.userprofile.cimar_sid
|
||||
"cimar_sid": request.user.userprofile.cimar_sid,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -2429,7 +2446,6 @@ def collection_case_dicom_json(request, exam_id, case_id):
|
||||
return JsonResponse(case_detail.case.get_case_dicom_json(priors=priors))
|
||||
|
||||
|
||||
|
||||
def case_dicom_json(request, pk):
|
||||
case = get_object_or_404(Case, pk=pk)
|
||||
|
||||
@@ -2925,19 +2941,25 @@ def collection_question_schemas(request, exam_id: int):
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def collection_reset_answers_user_list(request, exam_id: int):
|
||||
if request.htmx:
|
||||
collection = get_object_or_404(CaseCollection, pk=exam_id)
|
||||
cid_users = collection.cid_users.all()
|
||||
|
||||
if cid_users:
|
||||
return render(request, "atlas/collection_reset_answers_user_list.html", {"collection": collection, "cid_users": cid_users})
|
||||
return render(
|
||||
request,
|
||||
"atlas/collection_reset_answers_user_list.html",
|
||||
{"collection": collection, "cid_users": cid_users},
|
||||
)
|
||||
else:
|
||||
return HttpResponse("No user answers.")
|
||||
|
||||
else:
|
||||
raise Http404("Invalid request")
|
||||
|
||||
|
||||
def collection_reset_answers_user(request, exam_id: int, user_id: int):
|
||||
if request.htmx:
|
||||
collection = get_object_or_404(CaseCollection, pk=exam_id)
|
||||
@@ -2958,6 +2980,7 @@ def collection_reset_answers_user(request, exam_id: int, user_id: int):
|
||||
else:
|
||||
raise Http404("Invalid request")
|
||||
|
||||
|
||||
def collection_reset_answers(request, exam_id: int):
|
||||
if request.htmx:
|
||||
collection = get_object_or_404(CaseCollection, pk=exam_id)
|
||||
@@ -2983,8 +3006,8 @@ def collection_reset_answers(request, exam_id: int):
|
||||
else:
|
||||
raise Http404("Invalid request")
|
||||
|
||||
def push_case_to_cimar(request, case_id):
|
||||
|
||||
def push_case_to_cimar(request, case_id):
|
||||
push_case_to_cimar_task.delay(case_id=case_id)
|
||||
|
||||
return HttpResponse("Push started")
|
||||
@@ -3000,7 +3023,6 @@ def push_case_to_cimar(request, case_id):
|
||||
for image in series.images.all():
|
||||
data = api.upload_dicom(image.image.path, study_uid=study_uid)
|
||||
|
||||
|
||||
cimar_uuid = api.get_study_by_study_uid(data["study_uid"])["uuid"]
|
||||
|
||||
case.cimar_uuid = cimar_uuid
|
||||
@@ -3012,3 +3034,14 @@ def push_case_to_cimar(request, case_id):
|
||||
cimar_case.refresh_study()
|
||||
|
||||
return HttpResponse("Success")
|
||||
|
||||
|
||||
@require_POST
|
||||
def remove_case_from_collection(request, case_pk, collection_pk):
|
||||
case = get_object_or_404(Case, pk=case_pk)
|
||||
collection = get_object_or_404(CaseCollection, pk=collection_pk)
|
||||
|
||||
# Remove the case from the collection
|
||||
collection.cases.remove(case)
|
||||
|
||||
return HttpResponse(f"Case removed from collection: {collection.name}")
|
||||
|
||||
@@ -1337,4 +1337,11 @@ span#user-id {
|
||||
.marking-link:hover {
|
||||
color: #3282b8;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.remove-button {
|
||||
opacity: 20%;
|
||||
}
|
||||
.remove-button:hover {
|
||||
opacity: 100%;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user