diff --git a/atlas/CaseDetail, b/atlas/CaseDetail, new file mode 100644 index 00000000..e69de29b diff --git a/atlas/forms.py b/atlas/forms.py index d65050f1..48b88594 100755 --- a/atlas/forms.py +++ b/atlas/forms.py @@ -583,8 +583,10 @@ class SelfReviewForm(ModelForm): widgets = {"user_exam": HiddenInput(), "case": HiddenInput()} def __init__(self, *args, **kwargs): - user_exam_id = kwargs.pop("user_exam_id") - case_id = kwargs.pop("case_id") + if "user_exam_id" in kwargs: + user_exam_id = kwargs.pop("user_exam_id") + if "case_id" in kwargs: + case_id = kwargs.pop("case_id") ModelForm.__init__(self, *args, **kwargs) super(SelfReviewForm, self).__init__(*args, **kwargs) \ No newline at end of file diff --git a/atlas/migrations/0008_remove_case_scrapped_case_archive.py b/atlas/migrations/0008_remove_case_scrapped_case_archive.py new file mode 100644 index 00000000..07be81b5 --- /dev/null +++ b/atlas/migrations/0008_remove_case_scrapped_case_archive.py @@ -0,0 +1,22 @@ +# Generated by Django 4.1.4 on 2023-08-07 08:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('atlas', '0007_selfreview'), + ] + + operations = [ + migrations.RemoveField( + model_name='case', + name='scrapped', + ), + migrations.AddField( + model_name='case', + name='archive', + field=models.BooleanField(default=False, help_text='Case has been archived, this will remain on the system but will not be shown'), + ), + ] diff --git a/atlas/models.py b/atlas/models.py index 78ce2a79..3afc3ce5 100644 --- a/atlas/models.py +++ b/atlas/models.py @@ -13,6 +13,7 @@ from django.utils import timezone import pydicom +import pydicom.multival from django.core.files.storage import FileSystemStorage from django.conf import settings @@ -272,8 +273,9 @@ class Case(models.Model): related_name="atlas_edited_cases", ) - scrapped = models.BooleanField( - default=False, help_text="Question has been scrapped and will not be shown" + archive = models.BooleanField( + default=False, + help_text="Case has been archived, this will remain on the system but will not be shown", ) open_access = models.BooleanField( @@ -325,6 +327,30 @@ class Case(models.Model): examinations = [series.get_examination() for series in self.series.all()] return f"{self.pk}:{self.title} {'/'.join([str(c) for c in self.condition.all()])} [{', '.join(examinations)}]" + def get_case_dicom_json(self): + series_json = [] + for series in self.series.all(): + series_json.append(series.get_series_dicom_json()) + + print(series_json) + + return { + "studies": [ + { + "StudyInstanceUID": "1.3.6.1.4.1.14519.5.2.1.6279.6001.298806137288633453246975630178", + "StudyDate": "20000101", + "StudyTime": "", + "PatientName": "", + "PatientID": "LIDC-IDRI-0001", + "AccessionNumber": "", + "PatientAge": "", + "PatientSex": "", + "series": series_json, + } + ] + } + pass + class SeriesImage(SeriesImageBase): image = models.FileField(upload_to=image_directory_path) @@ -332,6 +358,50 @@ class SeriesImage(SeriesImageBase): "Series", related_name="images", on_delete=models.SET_NULL, null=True ) + def get_image_dicom_json(self): + try: + with pydicom.dcmread(self.image) as ds: + to_keep = [ + "Columns", + "Rows", + "InstanceNumber", + "SOPClassUID", + "PhotometricInterpretation", + "BitsAllocated", + "BitsStored", + "PixelRepresentation", + "SamplesPerPixel", + "PixelSpacing", + "HighBit", + "ImageOrientationPatient", + "ImagePositionPatient", + "FrameOfReferenceUID", + "ImageType", + "Modality", + "SOPInstanceUID", + "SeriesInstanceUID", + "StudyInstanceUID", + "WindowCenter", + "WindowWidth", + "SeriesDate", + ] + + d = {} + + for key in to_keep: + val = ds[key].value + + if type(val) == pydicom.multival.MultiValue: + d[key] = list(val) + else: + d[key] = val + + + + return {"metadata": d, "url": self.image.url} + except FileNotFoundError: + return [] + class SeriesFinding(models.Model): series = models.ForeignKey( @@ -411,6 +481,23 @@ class Series(SeriesBase): "{}", self.get_absolute_url(), self.get_full_str() ) + def get_series_dicom_json(self): + instances = [] + + image: SeriesImage + for image in self.images.all(): + instances.append(image.get_image_dicom_json()) + + series_json = { + "SeriesInstanceUID": "1.3.6.1.4.1.14519.5.2.1.6279.6001.179049373636438705059720603192", + "SeriesNumber": 3000566, + "Modality": "CT", + "SliceThickness": 2.5, + "instances": instances, + } + + return series_json + class CaseCollection(ExamCollectionGenericBase): app_name = "atlas" @@ -522,10 +609,14 @@ class CaseCollection(ExamCollectionGenericBase): return False - def get_case_by_index(self, case_index:int, case_count=False) -> Case | Tuple[Case, int]: + def get_case_by_index( + self, case_index: int, case_count=False + ) -> Case | Tuple[Case, int]: # Seems to be a bug when case_number is 0 or 1 the same (first) object gets returned # forces a list fixes (but is likely inefficient) - cases = list(self.cases.all().order_by("casedetail__sort_order").prefetch_related()) + cases = list( + self.cases.all().order_by("casedetail__sort_order").prefetch_related() + ) try: case = cases[case_index] @@ -534,10 +625,20 @@ class CaseCollection(ExamCollectionGenericBase): raise Http404(s) if case_count: - return case, len(cases) + return case, len(cases) else: return case + def get_case_take_url(self, case): + cases = list( + self.cases.all().order_by("casedetail__sort_order").prefetch_related() + ) + + return reverse( + "atlas:collection_case_view_take_user", + kwargs={"pk": self.pk, "case_number": cases.index(case)}, + ) + class CaseDetail(models.Model): case = models.ForeignKey(Case, on_delete=models.CASCADE) @@ -617,9 +718,7 @@ class SelfReview(models.Model): review_update_date = models.DateTimeField(auto_now=True) def get_absolute_url(self): - return reverse( - "atlas:collection_take_overview_user", kwargs={"pk": self.user_exam.exam.pk} - ) + return self.user_exam.exam.get_case_take_url(self.case) def get_display_block(self): html = """
@@ -628,15 +727,27 @@ class SelfReview(models.Model): Findings: {findings}
Interpretation: {interpretation}
- Date: {date}
+ Date: {date}
Edit
""" + edit_url = reverse( + "atlas:self_review_update", + kwargs={ + "user_exam_id": self.user_exam.pk, + "case_id": self.case.pk, + "pk": self.pk, + }, + ) + # edit_url = "TEST" + return format_html( html, comments=self.comments, findings=self.findings, interpretation=self.interpretation, date=self.review_date, + id=self.pk, + edit_url=edit_url, ) diff --git a/atlas/templates/atlas/collection_case_view_take.html b/atlas/templates/atlas/collection_case_view_take.html index 69570af4..b8d1789f 100644 --- a/atlas/templates/atlas/collection_case_view_take.html +++ b/atlas/templates/atlas/collection_case_view_take.html @@ -1,6 +1,7 @@ {% extends 'atlas/base.html' %} {% block content %} + Collection: {{collection}}

Case {{case_number|add:1}} {% if show_title %} @@ -75,6 +76,10 @@

{% endif %} + {% if collection.publish_results or cid_user_exam.completed %} + + + {% endif %}
{% csrf_token %} {% if collection.collection_type == "REP" %}
@@ -84,21 +89,22 @@

{% if completed %} -

Answer score: {{answer.score}}

- Answer feedback: {{answer.feedback|safe}} -
- {% if self_review %} -

Self Feedback

+ {% if collection.self_review %} + {% if self_review %} +

Self Feedback

- {% for review in self_review %} - {{review.get_display_block}} + {% for review in self_review %} + {{review.get_display_block}} - {% endfor %} + {% endfor %} + {% endif %} + {% else %} +

Answer score: {{answer.score}}

+ Answer feedback: {{answer.feedback|safe}} +
{% endif %} - - {% endif %}

@@ -117,10 +123,6 @@
- {% if collection.publish_results or cid_user_exam.completed %} - Add self review - - {% endif %}