start integrating cimar

This commit is contained in:
Ross
2025-02-24 11:53:36 +00:00
parent 249bc656c8
commit a0960c9b7c
21 changed files with 826 additions and 8 deletions
@@ -0,0 +1,18 @@
# Generated by Django 5.1.4 on 2025-02-10 12:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('generic', '0020_remove_examuserstatus_share_with_supervisor_and_more'),
]
operations = [
migrations.AddField(
model_name='userprofile',
name='cimar_sid',
field=models.CharField(blank=True, max_length=100),
),
]
+22
View File
@@ -0,0 +1,22 @@
# Generated by Django 5.1.4 on 2025-02-10 13:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('generic', '0021_userprofile_cimar_sid'),
]
operations = [
migrations.CreateModel(
name='CimarCase',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('uuid', models.CharField(max_length=255, unique=True)),
('viewer_link', models.URLField(blank=True)),
('study_details', models.JSONField(blank=True)),
],
),
]
@@ -0,0 +1,23 @@
# Generated by Django 5.1.4 on 2025-02-17 10:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('generic', '0022_cimarcase'),
]
operations = [
migrations.AddField(
model_name='cimarcase',
name='valid_uuid',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='cimarcase',
name='study_details',
field=models.JSONField(blank=True, default=dict),
),
]
@@ -0,0 +1,23 @@
# Generated by Django 5.1.4 on 2025-02-17 11:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('generic', '0023_cimarcase_valid_uuid_alter_cimarcase_study_details'),
]
operations = [
migrations.AddField(
model_name='cimarcase',
name='series_data',
field=models.JSONField(blank=True, default=dict),
),
migrations.AddField(
model_name='cimarcase',
name='study_schema',
field=models.JSONField(blank=True, default=dict),
),
]
+119 -2
View File
@@ -7,6 +7,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import models
from django.forms import ValidationError
from django.http import Http404, HttpRequest
from django.shortcuts import render
from django.utils import timezone
from django.core.validators import MaxValueValidator, MinValueValidator
from smtplib import SMTPException
@@ -29,7 +30,8 @@ from django.db.models.signals import post_save
from django.dispatch import receiver
from generic.mixins import AuthorMixin, QuestionMixin
from helpers.images import get_image_hash, pretty_print_dicom
from rad.settings import REMOTE_URL
from helpers.cimar import CimarAPI, STORAGE_API_URL
from rad.settings import REMOTE_URL, CIMAR_USERNAME, CIMAR_PASSWORD
from django.utils.html import format_html
from easy_thumbnails.files import get_thumbnailer
@@ -45,6 +47,34 @@ from django.forms.utils import from_current_timezone, to_current_timezone
from loguru import logger
from pygments import highlight
from pygments.lexers import JsonLexer
from pygments.formatters import HtmlFormatter
from django.contrib import admin
from django.utils.safestring import mark_safe
from django.template.loader import render_to_string
def get_pretty_json(data):
"""Function to display pretty version of our data"""
if not data:
return "No data"
# Convert the data to sorted, indented JSON
response = json.dumps(data, sort_keys=True, indent=2)
# Get the Pygments formatter
formatter = HtmlFormatter(style='colorful')
# Highlight the data
response = highlight(response, JsonLexer(), formatter)
# Get the stylesheet
style = "<style>" + formatter.get_style_defs() + "</style><br>"
# Safe the output
return mark_safe(style + response)
def findMiddle(input_list):
"""Returns the middle element of a list"""
@@ -1690,6 +1720,8 @@ class UserProfile(models.Model):
username = property(getusername)
cimar_sid = models.CharField(max_length=100, blank=True)
def get_exams(self):
available_exams = defaultdict(list)
@@ -1826,4 +1858,89 @@ class ExamCollection(models.Model, AuthorMixin):
# settings.AUTH_USER_MODEL,
# blank=True,
# help_text="Author/Manager(s) of the exam collection",
# )
# )
class CimarCase(models.Model):
uuid = models.CharField(max_length=255, unique=True)
viewer_link = models.URLField(blank=True)
study_details = models.JSONField(blank=True, default=dict)
study_schema = models.JSONField(blank=True, default=dict)
series_data = models.JSONField(blank=True, default=dict)
valid_uuid = models.BooleanField(default=False)
def load_series_data(self, api=None):
if api is None:
api = CimarAPI()
api.login(username=CIMAR_USERNAME, password=CIMAR_PASSWORD)
def refresh_study(self):
api = CimarAPI()
api.login(username=CIMAR_USERNAME, password=CIMAR_PASSWORD)
self.study_details = api.get_study_by_uuid(self.uuid)
self.study_schema = api.get_study_schema_by_uuid(self.uuid)
self.viewer_link = api.get_study_viewer_url_by_uuid(self.uuid)
series_data = []
for series in self.study_schema["series"]:
series_data.append({
"series_id" : series["id"],
"series_description" : series["description"],
"image_count": len(series["images"]),
"thumbnail": self.get_series_image_thumbnail_link(series)
}
)
self.series_data = {}
self.series_data["series"] = series_data
self.valid_uuid = True
self.save()
def __str__(self):
return f"{self.uuid} ({self.valid_uuid})"
def get_user_viewer_link(self, user):
return self.viewer_link + f"?sid={user.userprofile.cimar_sid}"
def get_pretty_study_details(self):
"""Function to display pretty version of our data"""
return get_pretty_json(self.study_details)
def get_pretty_study_schema(self):
"""Function to display pretty version of our data"""
return get_pretty_json(self.study_schema)
def get_pretty_study_series(self):
"""Function to display pretty version of our data"""
return get_pretty_json(self.series_data)
#def get_series_details_block(self, cimar_sid=None):
# if "series" in self.series_data:
# return render_to_string("cimar_series.html", {"series_data": self.series_data["series"], cimar_sid: cimar_sid})
#
# return "No series data available"
# return render_to_string("cimar_series.html", {"series_data": self.series_data["series"]})
def get_series_image_thumbnail_link(self,series):
middle_point = len(series["images"]) // 2
image = series["images"][middle_point]
return STORAGE_API_URL + f"/study/{self.study_details["storage_namespace"]}/{self.study_details["study_uid"]}/image/{image["id"]}/version/{image["version"]}/frame/0/thumbnail"
+7
View File
@@ -243,6 +243,13 @@ urlpatterns = [
views.toggle_share_with_supervisor,
name="toggle_share_with_supervisor",
),
path(
"cimar_case/<str:uuid>/refresh",
views.cimar_case_refresh,
name="cimar_case_refresh"
),
]
+15 -1
View File
@@ -84,6 +84,7 @@ from .models import (
CidUser,
CidUserExam,
CidUserGroup,
CimarCase,
ExamBase,
ExamCollection,
ExamUserStatus,
@@ -4084,4 +4085,17 @@ def exam_collection_add_marker(request, collection_id, exam_type):
collection.add_marker_to_exams(users, exam_types=(exam_type,))
return HttpResponse("Marker added to exams")
return HttpResponse("Marker added to exams")
def cimar_case_refresh(request, uuid):
try:
CimarCase.objects.get(uuid=uuid).refresh_study()
except CimarCase.DoesNotExist:
CimarCase(uuid=uuid).save()
return HttpResponse("Case refreshed")