From 5e578ca2b0746c9e79821e5445fc2f9baeac2080 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 28 Apr 2025 15:45:02 +0100 Subject: [PATCH] improve case management --- atlas/models.py | 9 ++++ atlas/templates/atlas/case_display_block.html | 17 +++++- .../atlas/collection_case_view_take.html | 2 +- atlas/templates/atlas/selfreview_form.html | 1 + atlas/urls.py | 5 ++ atlas/views.py | 53 +++++++++++++++---- rad/static/css/anatomy.css | 9 +++- 7 files changed, 83 insertions(+), 13 deletions(-) diff --git a/atlas/models.py b/atlas/models.py index 1119ef3a..99b9b8bd 100644 --- a/atlas/models.py +++ b/atlas/models.py @@ -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 + diff --git a/atlas/templates/atlas/case_display_block.html b/atlas/templates/atlas/case_display_block.html index da0c9950..0077c8c8 100755 --- a/atlas/templates/atlas/case_display_block.html +++ b/atlas/templates/atlas/case_display_block.html @@ -248,14 +248,29 @@ Diagnostic certainty: {{case.get_diagnostic_certainty_display}}
Collections: + + {% if can_edit %} + {% endif %}

diff --git a/atlas/templates/atlas/collection_case_view_take.html b/atlas/templates/atlas/collection_case_view_take.html index 4b2365d4..934ccbed 100644 --- a/atlas/templates/atlas/collection_case_view_take.html +++ b/atlas/templates/atlas/collection_case_view_take.html @@ -218,7 +218,7 @@
{% if collection.self_review %}

- +

{% if self_review %}

Self Feedback

diff --git a/atlas/templates/atlas/selfreview_form.html b/atlas/templates/atlas/selfreview_form.html index 1e9aaf2c..5d1f48c9 100644 --- a/atlas/templates/atlas/selfreview_form.html +++ b/atlas/templates/atlas/selfreview_form.html @@ -8,6 +8,7 @@ Adding self feedback for {{user_exam.exam}}/{{case}}
+ 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.
{% csrf_token %} {{ form.non_field_errors }} diff --git a/atlas/urls.py b/atlas/urls.py index a228afba..43ac7064 100755 --- a/atlas/urls.py +++ b/atlas/urls.py @@ -249,6 +249,11 @@ urlpatterns = [ views.use_dates_as_descriptions, name="use_dates_as_descriptions", ), + path( + "case//collection//remove/", + views.remove_case_from_collection, + name="remove_case_from_collection", + ), path( "series//dicom_json", views.series_dicom_json, diff --git a/atlas/views.py b/atlas/views.py index d5301fa2..d1285365 100755 --- a/atlas/views.py +++ b/atlas/views.py @@ -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}") diff --git a/rad/static/css/anatomy.css b/rad/static/css/anatomy.css index 4bb99a47..d0a55500 100644 --- a/rad/static/css/anatomy.css +++ b/rad/static/css/anatomy.css @@ -1337,4 +1337,11 @@ span#user-id { .marking-link:hover { color: #3282b8; text-decoration: underline; -} \ No newline at end of file +} + +.remove-button { + opacity: 20%; +} +.remove-button:hover { + opacity: 100%; +}