start integrating cimar
This commit is contained in:
@@ -67,6 +67,9 @@ from atlas.helpers import get_cases_available_to_user
|
||||
|
||||
from typing import Any
|
||||
|
||||
from helpers.cimar import CimarAPI, NotFoundError
|
||||
from rad.settings import CIMAR_USERNAME, CIMAR_PASSWORD
|
||||
|
||||
class CaseSelect(Select):
|
||||
template_name = "atlas/case_select_widget.html"
|
||||
|
||||
@@ -363,6 +366,7 @@ class CaseForm(ModelForm):
|
||||
"open_access",
|
||||
"previous_case",
|
||||
"diagnostic_certainty",
|
||||
"cimar_uuid"
|
||||
),
|
||||
|
||||
)
|
||||
@@ -396,6 +400,7 @@ class CaseForm(ModelForm):
|
||||
"open_access",
|
||||
"previous_case",
|
||||
"diagnostic_certainty",
|
||||
"cimar_uuid"
|
||||
]
|
||||
# fields = ['question', 'findings', 'subspecialty', 'references']
|
||||
widgets = {
|
||||
@@ -417,6 +422,18 @@ class CaseForm(ModelForm):
|
||||
"pathological_process": CheckboxSelectMultiple(),
|
||||
"previous_case": CaseSelect(),
|
||||
}
|
||||
|
||||
def clean_cimar_uuid(self):
|
||||
cimar_uuid = self.cleaned_data["cimar_uuid"]
|
||||
if cimar_uuid:
|
||||
with CimarAPI(username=CIMAR_USERNAME, password=CIMAR_PASSWORD) as api:
|
||||
try:
|
||||
study = api.get_study_by_uuid(cimar_uuid)
|
||||
|
||||
except NotFoundError:
|
||||
raise ValidationError("Study not found in CIMAR")
|
||||
|
||||
return cimar_uuid
|
||||
|
||||
def save(self, commit=True):
|
||||
# Get the unsaved Case instance
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.4 on 2025-02-10 13:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('atlas', '0066_case_total_images_series_size'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='case',
|
||||
name='cimar_uuid',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
]
|
||||
@@ -46,6 +46,7 @@ from generic.models import (
|
||||
CidUser,
|
||||
CidUserExam,
|
||||
CidUserGroup,
|
||||
CimarCase,
|
||||
ExamOrCollectionGenericBase,
|
||||
ExamUserStatus,
|
||||
Examination,
|
||||
@@ -392,6 +393,8 @@ class Case(models.Model, AuthorMixin, QuestionMixin):
|
||||
|
||||
total_images_series_size = models.BigIntegerField(null=True, blank=True)
|
||||
|
||||
cimar_uuid = models.CharField(max_length=255, null=True, blank=True)
|
||||
|
||||
def get_app_name(self):
|
||||
return "atlas"
|
||||
|
||||
@@ -404,6 +407,14 @@ class Case(models.Model, AuthorMixin, QuestionMixin):
|
||||
# return f"{self.pk}: {self.title}"
|
||||
return format_html("<a href='{}'>{}</a>", self.get_absolute_url(), str(self))
|
||||
|
||||
def get_cimar_case(self):
|
||||
return get_object_or_404(CimarCase, uuid=self.cimar_uuid)
|
||||
|
||||
def get_cimar_case_details(self):
|
||||
cimar_case = self.get_cimar_case()
|
||||
return cimar_case.study_details
|
||||
|
||||
|
||||
# def get_base_template(self):
|
||||
|
||||
# def get_edit_template_links(self):
|
||||
@@ -427,6 +438,7 @@ class Case(models.Model, AuthorMixin, QuestionMixin):
|
||||
|
||||
def get_case_dicom_json(self, case_title_as_patient_name=True, priors=None):
|
||||
series_json = []
|
||||
series: Series
|
||||
for series in self.series.all():
|
||||
series_json.append(series.get_series_dicom_json())
|
||||
|
||||
@@ -506,6 +518,8 @@ class Case(models.Model, AuthorMixin, QuestionMixin):
|
||||
|
||||
return size
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,65 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div><a href="/ohif/viewer/dicomjson?url=https://www.penracourses.org.uk{% url 'atlas:case_dicom_json' case.pk %}">View case in OHIF</a> <a target="_blank" href="/ohif/viewer/dicomjson?url=https://www.penracourses.org.uk{% url 'atlas:case_dicom_json' case.pk %}">(new tab)</a>
|
||||
<div>
|
||||
|
||||
{% if case.cimar_uuid %}
|
||||
|
||||
<details><summary>Details</summary>
|
||||
<br/>
|
||||
Case uuid: {{case.cimar_uuid}}
|
||||
<br/>
|
||||
{{case.get_cimar_case.viewer_link}}?{{cimar_sid}}
|
||||
|
||||
<button
|
||||
hx-get='{% url "cimar_study_viewer_embed" case.cimar_uuid %}'
|
||||
hx-target="#modals-here"
|
||||
hx-trigger="click"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#modals-here"
|
||||
class="btn primary">Open Modal</button>
|
||||
|
||||
<div id="modals-here"
|
||||
class="modal modal-blur fade"
|
||||
style="display: none"
|
||||
aria-hidden="false"
|
||||
tabindex="-1">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
|
||||
<div class="modal-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href='{% url "cimar_study_viewer" case.cimar_uuid %}'>Viewer</a>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Study details</summary>
|
||||
{{ case.get_cimar_case.get_pretty_study_details }}
|
||||
</details>
|
||||
<details>
|
||||
<summary>Study schema</summary>
|
||||
{{ case.get_cimar_case.get_pretty_study_schema }}
|
||||
</details>
|
||||
<details>
|
||||
<summary>Study series</summary>
|
||||
<button
|
||||
id='load-series'
|
||||
hx-get='{% url "cimar_study_series_block" case.cimar_uuid %}'
|
||||
hx-trigger='load'
|
||||
hx-swap='outerHTML'>
|
||||
Load Series
|
||||
</button>
|
||||
</details>
|
||||
<a href='{% url "generic:cimar_case_refresh" case.cimar_uuid %}'>Refresh</a>
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
{% else %}
|
||||
<a href="/ohif/viewer/dicomjson?url=https://www.penracourses.org.uk{% url 'atlas:case_dicom_json' case.pk %}">View case in OHIF</a> <a target="_blank" href="/ohif/viewer/dicomjson?url=https://www.penracourses.org.uk{% url 'atlas:case_dicom_json' case.pk %}">(new tab)</a>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="date">
|
||||
{{ case.created_date|date:"d/m/Y" }}
|
||||
|
||||
@@ -378,6 +378,7 @@ urlpatterns = [
|
||||
# path("all_questions/", views.all_questions, name="all_questions"),
|
||||
path("case/<int:pk>/scrap", views.atlas_scrap, name="case_scrap"),
|
||||
path("case/<int:pk>/delete", views.CaseDelete.as_view(), name="case_delete"),
|
||||
path("case/<int:case_id>/push_to_cimar", views.push_case_to_cimar, name="push_case_to_cimar"),
|
||||
path("case/create/", views.AtlasCreate.as_view(), name="case_create"),
|
||||
path(
|
||||
"case/collection/<int:pk>/create",
|
||||
|
||||
+37
-2
@@ -22,6 +22,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMix
|
||||
from django.views.generic import View
|
||||
from django.views.generic.detail import DetailView
|
||||
import pydicom
|
||||
from pydicom.uid import generate_uid
|
||||
from generic.mixins import SuperuserRequiredMixin
|
||||
|
||||
from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView
|
||||
@@ -33,8 +34,9 @@ from django.urls import reverse_lazy, reverse
|
||||
from django.http import Http404, JsonResponse
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
|
||||
from generic.models import CidUser, CidUserExam
|
||||
from generic.models import CidUser, CidUserExam, CimarCase
|
||||
from atlas.helpers import get_cases_available_to_user
|
||||
from rad.settings import REMOTE_URL, CIMAR_USERNAME, CIMAR_PASSWORD
|
||||
|
||||
from .forms import (
|
||||
AddCollectionToCaseForm,
|
||||
@@ -159,6 +161,8 @@ import reversion
|
||||
import os
|
||||
import difflib
|
||||
|
||||
from helpers.cimar import CimarAPI
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -195,7 +199,7 @@ def case_detail(request, pk):
|
||||
# raise PermissionDenied
|
||||
|
||||
# logging.debug(atlas.subspecialty.first().name.all())
|
||||
return render(request, "atlas/case_detail.html", {"case": case})
|
||||
return render(request, "atlas/case_detail.html", {"case": case, "cimar_sid":request.user.userprofile.cimar_sid})
|
||||
|
||||
@login_required
|
||||
@user_is_author_or_atlas_series_checker_or_atlas_marker_or_open_access
|
||||
@@ -955,6 +959,9 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin):
|
||||
|
||||
form.instance.author.add(self.request.user.id)
|
||||
|
||||
# Check Cimar Case
|
||||
#CimarAPI().get_study_by_uuid(self.object.cimar_uuid)
|
||||
|
||||
context = self.get_context_data(form=form)
|
||||
series_formset = context["series_formset"]
|
||||
casedifferential_formset = context["casedifferential_formset"]
|
||||
@@ -2390,6 +2397,7 @@ def collection_case_view(request, pk, case_number):
|
||||
"previous": previous,
|
||||
"next": next,
|
||||
"answer": answer,
|
||||
"cimar_sid":request.user.userprofile.cimar_sid
|
||||
},
|
||||
)
|
||||
|
||||
@@ -2419,6 +2427,7 @@ 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)
|
||||
|
||||
@@ -2971,3 +2980,29 @@ def collection_reset_answers(request, exam_id: int):
|
||||
|
||||
else:
|
||||
raise Http404("Invalid request")
|
||||
|
||||
def push_case_to_cimar(request, case_id):
|
||||
case = get_object_or_404(Case, pk=case_id)
|
||||
|
||||
api = CimarAPI()
|
||||
api.login(username=CIMAR_USERNAME, password=CIMAR_PASSWORD)
|
||||
|
||||
# We use the same study_uid for all images in a case
|
||||
study_uid = generate_uid()
|
||||
|
||||
for series in case.get_series():
|
||||
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
|
||||
|
||||
case.save()
|
||||
|
||||
cimar_case, created = CimarCase.objects.get_or_create(uuid=cimar_uuid)
|
||||
|
||||
cimar_case.refresh_study()
|
||||
|
||||
return HttpResponse("Success")
|
||||
|
||||
Reference in New Issue
Block a user