i should break these commits up

This commit is contained in:
Ross
2024-04-08 14:16:13 +01:00
parent f13d1ba7e2
commit 98756baa37
25 changed files with 839 additions and 366 deletions
+162 -48
View File
@@ -31,6 +31,7 @@ from django.http import Http404, JsonResponse
from django.http import HttpResponseRedirect, HttpResponse
from generic.models import CidUser, CidUserExam
from atlas.helpers import get_cases_available_to_user
from .forms import (
AddCollectionToCaseForm,
@@ -45,6 +46,7 @@ from .forms import (
ConditionAutocompleteForm,
ConditionForm,
FindingForm,
ResourceForm,
SelfReviewForm,
SeriesForm,
SeriesImageFormSet,
@@ -63,6 +65,7 @@ from .models import (
Differential,
PathologicalProcess,
Presentation,
Resource,
SelfReview,
Series,
Examination,
@@ -127,7 +130,12 @@ import logging
from copy import deepcopy
from django.forms.models import model_to_dict
from generic.views import AuthorRequiredMixin, ExamCloneMixin, ExamViews, SeriesImagesZipViewBase
from generic.views import (
AuthorRequiredMixin,
ExamCloneMixin,
ExamViews,
SeriesImagesZipViewBase,
)
from reversion.views import RevisionMixin
import reversion
@@ -139,14 +147,6 @@ 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):
@@ -160,6 +160,7 @@ class AuthorOrCheckerRequiredMixin(object):
raise PermissionDenied() # or Http404
return obj
class AtlasEditorRequiredMixin(object):
def get_object(self, *args, **kwargs):
obj = super().get_object(*args, **kwargs)
@@ -170,6 +171,7 @@ class AtlasEditorRequiredMixin(object):
return obj
raise PermissionDenied("You must be an atlas editor to do this.") # or Http404
@login_required
@user_has_case_view_access
def case_detail(request, pk):
@@ -208,7 +210,7 @@ def series_detail(request, pk, finding_pk=None):
@login_required
#@user_is_atlas_editor
# @user_is_atlas_editor
def condition_detail(request, pk):
condition = get_object_or_404(Condition, pk=pk)
@@ -216,7 +218,10 @@ def condition_detail(request, pk):
can_merge = False
if request.user.is_superuser or request.user.groups.filter(name="atlas_editor").exists():
if (
request.user.is_superuser
or request.user.groups.filter(name="atlas_editor").exists()
):
can_merge = True
# logging.debug(atlas.subspecialty.first().name.all())
@@ -275,7 +280,7 @@ def condition_merge(request, pk_to_merge):
@login_required
#@user_is_atlas_editor
# @user_is_atlas_editor
def subspecialty_detail(request, pk):
subspecialty = get_object_or_404(Subspecialty, pk=pk)
@@ -290,7 +295,7 @@ def subspecialty_detail(request, pk):
@login_required
#@user_is_atlas_editor
# @user_is_atlas_editor
def presentation_detail(request, pk):
presentation = get_object_or_404(Presentation, pk=pk)
@@ -305,7 +310,7 @@ def presentation_detail(request, pk):
@login_required
#@user_is_atlas_editor
# @user_is_atlas_editor
def pathological_process_detail(request, pk):
pathological_process = get_object_or_404(PathologicalProcess, pk=pk)
@@ -320,7 +325,7 @@ def pathological_process_detail(request, pk):
@login_required
#@user_is_atlas_editor
# @user_is_atlas_editor
def structure_detail(request, pk):
structure = get_object_or_404(Structure, pk=pk)
@@ -335,7 +340,7 @@ def structure_detail(request, pk):
@login_required
#@user_is_atlas_editor
# @user_is_atlas_editor
def finding_detail(request, pk):
finding = get_object_or_404(Finding, pk=pk)
@@ -349,6 +354,13 @@ def finding_detail(request, pk):
)
@login_required
def resource_detail(request, pk):
resource = get_object_or_404(Resource, pk=pk)
return render(request, "atlas/resource_detail.html", {"resource": resource})
@login_required
def author_detail(request, pk):
# logging.debug(Author.objects.all())
@@ -381,11 +393,11 @@ 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":
@@ -395,14 +407,18 @@ def add_case_to_collection(request, collection_id):
return HttpResponse("Case already in collection")
print(case)
collection.add_case(case)
return HttpResponse("Case added to collection")
return HttpResponse("Case added to collection (refresh to see)")
#if request.method == "POST":
# 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})
return render(
request,
"atlas/add_case_to_collection.html",
{"cases": cases, "collection": collection},
)
@login_required
def user_uploads_series(request, series_instance_uid: str):
@@ -418,17 +434,25 @@ def user_uploads_series(request, series_instance_uid: str):
{"dicoms": dicoms, "series_id": series_instance_uid},
)
@login_required
@user_passes_test(lambda u: u.is_superuser)
def all_uploads(request, case_id: int | None = None):
return user_uploads(request, case_id, user_only=False)
@user_passes_test(lambda u: u.is_superuser)
def other_user_uploads(request, user_pk: int, case_id: int | None = None):
return user_uploads(request, case_id, user_only=False, user_pk=user_pk)
@login_required
def user_uploads(request, case_id: int | None = None, user_only: bool = True, user_pk: int | None = None):
def user_uploads(
request,
case_id: int | None = None,
user_only: bool = True,
user_pk: int | None = None,
):
user = request.user
if user_only:
dicoms = UncategorisedDicom.objects.filter(user=request.user)
@@ -446,7 +470,6 @@ def user_uploads(request, case_id: int | None = None, user_only: bool = True, us
d.save()
tags = d.basic_dicom_tags
data[tags["SeriesInstanceUID"]].append((tags, d.created_date))
series_list = []
@@ -461,7 +484,9 @@ def user_uploads(request, case_id: int | None = None, user_only: bool = True, us
case = get_object_or_404(Case, pk=case_id)
return render(
request, "atlas/user_uploads.html", {"series_list": series_list, "case": case, "user": user}
request,
"atlas/user_uploads.html",
{"series_list": series_list, "case": case, "user": user},
)
@@ -513,9 +538,34 @@ class StructureDelete(RevisionMixin, AtlasEditorRequiredMixin, DeleteView):
success_url = reverse_lazy("atlas:structure_view")
class ResourceDelete(LoginRequiredMixin, DeleteView):
model = Resource
template_name = "confirm_delete.html"
success_url = reverse_lazy("atlas:resource_view")
class ResourceCreate(LoginRequiredMixin, CreateView):
model = Resource
form_class = ResourceForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.save()
form.instance.author.add(self.request.user.id)
return super().form_valid(form)
class ResourceView(LoginRequiredMixin, ListView):
model = Resource
# form_class = ResourceForm
class CaseCollectionCreate(RevisionMixin, LoginRequiredMixin, CreateView):
model = CaseCollection
form_class = CaseCollectionForm
template_name = "atlas/casecollection_form.html"
def get_initial(self):
# print(self.request)
@@ -553,7 +603,6 @@ class CaseCollectionCreate(RevisionMixin, LoginRequiredMixin, CreateView):
self.object.save()
form.instance.author.add(self.request.user.id)
context = self.get_context_data(form=form)
case_formset = context["case_formset"]
if case_formset.is_valid():
@@ -618,7 +667,7 @@ class SeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView):
class CaseCollectionUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateView):
model = CaseCollection
form_class = CaseCollectionForm
template_name = "atlas/collection_update_form.html"
template_name = "atlas/casecollection_form.html"
# fields = '__all__'
# #fields = [ 'condition' ]
@@ -724,6 +773,18 @@ class SeriesUpdate(
return super().form_invalid(form)
class ResourceUpdate(LoginRequiredMixin, UpdateView):
model = Resource
form_class = ResourceForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.save()
form.instance.author.add(self.request.user.id)
return super().form_valid(form)
class ConditionUpdate(RevisionMixin, LoginRequiredMixin, UpdateView):
model = Condition
form_class = ConditionForm
@@ -775,7 +836,8 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin):
self.request.POST, self.request.FILES
)
context["caseresource_formset"] = CaseResourceFormSet(
self.request.POST, self.request.FILES,
self.request.POST,
self.request.FILES,
form_kwargs={"user": self.request.user},
)
context["series_formset"].full_clean()
@@ -805,7 +867,11 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin):
series_formset = context["series_formset"]
casedifferential_formset = context["casedifferential_formset"]
caseresource_formset = context["caseresource_formset"]
if series_formset.is_valid() and casedifferential_formset.is_valid() and caseresource_formset.is_valid():
if (
series_formset.is_valid()
and casedifferential_formset.is_valid()
and caseresource_formset.is_valid()
):
response = super().form_valid(form)
series_formset.instance = self.object
series_formset.save()
@@ -871,8 +937,15 @@ class AtlasUpdate(
context["casedifferential_formset"] = CaseDifferentialFormSet(
self.request.POST, self.request.FILES, instance=self.object
)
context["caseresource_formset"] = CaseResourceFormSet(
self.request.POST,
self.request.FILES,
instance=self.object,
form_kwargs={"user": self.request.user},
)
context["series_formset"].full_clean()
context["casedifferential_formset"].full_clean()
context["caseresource_formset"].full_clean()
else:
context["series_formset"] = SeriesFormSet(
instance=self.object, form_kwargs={"user": self.request.user}
@@ -880,6 +953,10 @@ class AtlasUpdate(
context["casedifferential_formset"] = CaseDifferentialFormSet(
instance=self.object
)
context["caseresource_formset"] = CaseResourceFormSet(
instance=self.object,
form_kwargs={"user": self.request.user},
)
return context
def form_valid(self, form):
@@ -891,13 +968,20 @@ class AtlasUpdate(
context = self.get_context_data(form=form)
series_formset = context["series_formset"]
casedifferential_formset = context["casedifferential_formset"]
caseresource_formset = context["caseresource_formset"]
# logger.debug(formset.is_valid())
if series_formset.is_valid() and casedifferential_formset.is_valid():
if (
series_formset.is_valid()
and casedifferential_formset.is_valid()
and caseresource_formset.is_valid()
):
response = super().form_valid(form)
series_formset.instance = self.object
series_formset.save()
casedifferential_formset.instance = self.object
casedifferential_formset.save()
caseresource_formset.instance = self.object
caseresource_formset.save()
return response
else:
@@ -970,7 +1054,6 @@ class AtlasClone(AtlasCreateBase, AuthorOrCheckerRequiredMixin, CreateView):
return initial_data
@login_required
@user_is_author_or_atlas_editor
def atlas_scrap(request, pk):
@@ -1069,6 +1152,7 @@ class FindingView(LoginRequiredMixin, SingleTableMixin, FilterView):
filterset_class = FindingFilter
@login_required
def case_order_dicom(request, pk):
if request.htmx:
@@ -1086,11 +1170,12 @@ def case_order_dicom(request, pk):
fail.append(series.pk)
if fail:
return HttpResponse(f"Unable to order series {','.join([str(i) for i in fail])}")
return HttpResponse(
f"Unable to order series {','.join([str(i) for i in fail])}"
)
else:
return HttpResponse("Series reordered")
raise Http404
@@ -1105,6 +1190,7 @@ def series_order_dicom(request, pk):
return redirect("atlas:series_detail", pk=pk)
@login_required
def image_diff(request):
if request.htmx:
@@ -1116,23 +1202,23 @@ def image_diff(request):
second: SeriesImage = get_object_or_404(SeriesImage, pk=image_ids[1])
first_ds = pydicom.read_file(first.image.file)
#del first_ds.PixelData
#j1 = first_ds.to_json_dict()
# del first_ds.PixelData
# j1 = first_ds.to_json_dict()
f = print_dicom(first_ds, join=False)
second_ds = pydicom.read_file(second.image.file)
#del second_ds.PixelData
#j2 = second_ds.to_json_dict()
# del second_ds.PixelData
# j2 = second_ds.to_json_dict()
s = print_dicom(second_ds, join=False)
diff = difflib.HtmlDiff().make_table(f, s)
dict_diff = pprint.pformat(compare_dicom_datasets(first_ds, second_ds))
#return HttpResponse(diff)
# return HttpResponse(diff)
return HttpResponse(f"<pre>{dict_diff}</pre><br/>{diff}")
else:
ds_set = []
for pk in image_ids:
@@ -1142,7 +1228,6 @@ def image_diff(request):
dict_diff = pprint.pformat(compare_dicom_datasets(*ds_set))
return HttpResponse(f"<pre>{dict_diff}</pre>")
return HttpResponse("Fail")
@@ -1366,6 +1451,7 @@ class CollectionView(LoginRequiredMixin, SingleTableMixin, FilterView):
filterset_class = CaseCollectionFilter
@user_is_collection_author_or_atlas_editor
def collection_viva(request, pk):
collection = get_object_or_404(CaseCollection, pk=pk)
@@ -1378,11 +1464,12 @@ def collection_viva(request, pk):
{"collection": collection, "cases": cases, "can_edit": True},
)
@user_is_collection_author_or_atlas_editor
def collection_viva_case(request, pk, case_number):
collection = get_object_or_404(CaseCollection, pk=pk)
#cases = collection.cases.all().order_by("casedetail__sort_order")
# cases = collection.cases.all().order_by("casedetail__sort_order")
current_case = collection.get_case_by_index(case_number)
return render(
@@ -1391,6 +1478,7 @@ def collection_viva_case(request, pk, case_number):
{"collection": collection, "current_case": current_case},
)
@user_is_collection_author_or_atlas_editor
def collection_viva_series(request, pk, series_id):
collection = get_object_or_404(CaseCollection, pk=pk)
@@ -1408,8 +1496,10 @@ def collection_viva_series(request, pk, series_id):
def collection_detail(request, pk):
collection = get_object_or_404(CaseCollection, pk=pk)
#cases = collection.cases.all().order_by("casedetail__sort_order")
casedetails = CaseDetail.objects.filter(collection=collection).order_by("sort_order")
# cases = collection.cases.all().order_by("casedetail__sort_order")
casedetails = CaseDetail.objects.filter(collection=collection).order_by(
"sort_order"
)
return render(
request,
@@ -1725,12 +1815,20 @@ def collection_case_view_take(
else:
form = ReportAnswerForm(request.POST)
if not cid_user_exam.completed:
if not cid_user_exam.completed and not (
answer is not None and answer.completed
):
if form.is_valid():
answer = form.save(commit=False)
answer.set_cid_or_user(cid=cid, user=request.user)
answer.question = case_detail
# answer.published_date = timezone.now()
if "complete_case" in request.POST:
if not collection.self_review:
raise Http404("Self review not enabled")
answer.completed = True
answer.save()
cid_user_exam.end_time = timezone.now()
@@ -1769,7 +1867,11 @@ def collection_case_view_take(
# Set what details a user is / is not able to view when taking the case
# this can be configured via the collection edit menu
if collection.publish_results or cid_user_exam.completed:
if (
collection.publish_results
or cid_user_exam.completed
or (answer is not None and answer.completed)
):
completed = True
show_title = collection.show_title_post
show_history = collection.show_history_post
@@ -1778,6 +1880,8 @@ def collection_case_view_take(
show_report = collection.show_report_post
self_review = cid_user_exam.selfreview_set.filter(case=case)
resources = case.caseresource_set.all()
else:
completed = False
show_title = collection.show_title_pre
@@ -1787,6 +1891,8 @@ def collection_case_view_take(
show_report = collection.show_report_pre
self_review = []
resources = case.caseresource_set.filter(pre_review=True)
return render(
request,
"atlas/collection_case_view_take.html",
@@ -1806,6 +1912,7 @@ def collection_case_view_take(
"show_description": show_description,
"show_discussion": show_discussion,
"show_report": show_report,
"resources": resources,
"cid_user_exam": cid_user_exam,
"completed": completed,
"self_review": self_review,
@@ -1856,11 +1963,13 @@ def collection_case_view(request, pk, case_number):
},
)
def collection_dicom_json(request, pk):
collection = get_object_or_404(CaseCollection, pk=pk)
return JsonResponse(collection.get_ohif_dicom_json())
@user_is_author_or_atlas_editor
def use_dates_as_descriptions(request, pk):
case = get_object_or_404(Case, pk=pk)
@@ -1871,16 +1980,19 @@ def use_dates_as_descriptions(request, pk):
return HttpResponse("Done")
def case_dicom_json(request, pk):
case = get_object_or_404(Case, pk=pk)
return JsonResponse(case.get_case_dicom_json())
def series_dicom_json(request, pk):
series = get_object_or_404(Series, pk=pk)
return JsonResponse(series.get_ohif_dicom_json())
@user_is_collection_author_or_atlas_editor
def delete_collection_cid_answers(request, exam_id, cid):
collection = get_object_or_404(CaseCollection, pk=exam_id)
@@ -2227,7 +2339,7 @@ def combine_series(request):
it will not migrate other models such as SeriesFinding or other details
"""
series_ids = request.POST.getlist("series-ids")
#series = get_object_or_404(Series, pk=series_id)
# series = get_object_or_404(Series, pk=series_id)
if len(series_ids) < 2:
return HttpResponse("Not enough series to combine")
@@ -2252,7 +2364,8 @@ def combine_series(request):
series.delete()
return HttpResponse(f"Series {series_ids} combines")
#return HttpResponse("Fail")
# return HttpResponse("Fail")
class CaseCollectionAuthorUpdate(RevisionMixin, AuthorRequiredMixin, UpdateView):
model = CaseCollection
@@ -2264,6 +2377,7 @@ class CaseCollectionAuthorUpdate(RevisionMixin, AuthorRequiredMixin, UpdateView)
context["collection"] = context["object"]
return context
class CaseAuthorUpdate(RevisionMixin, AuthorRequiredMixin, UpdateView):
model = Case
form_class = CaseAuthorForm
@@ -2272,4 +2386,4 @@ class CaseAuthorUpdate(RevisionMixin, AuthorRequiredMixin, UpdateView):
def get_context_data(self, **kwargs):
context = super(CaseAuthorUpdate, self).get_context_data(**kwargs)
context["collection"] = context["object"]
return context
return context