From d891c7b9eed769b7493bc3cea93a27dcf970cc4a Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 6 Jan 2025 11:14:34 +0000 Subject: [PATCH] . --- Dockerfile | 10 ++++++++-- anatomy/models.py | 3 +++ anatomy/templates/anatomy/mark.html | 10 +++++----- atlas/templates/atlas/case_display_block.html | 8 +++++++- atlas/urls.py | 2 ++ atlas/views.py | 18 ++++++++++++++---- docker/docker-compose.yml | 2 -- generic/models.py | 8 ++++++-- generic/views.py | 3 +++ helpers/images.py | 2 +- requirements.txt | 5 +++-- 11 files changed, 52 insertions(+), 19 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2c2bbdf9..e3fb9059 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,6 @@ # pull official base image FROM python:3.12.1-slim +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ # set work directory WORKDIR /usr/src/rad @@ -17,9 +18,14 @@ RUN apt-get update && apt-get -y install postgresql postgresql-contrib git libca # install dependencies -RUN pip install --upgrade pip +#RUN pip install --upgrade pip COPY ./requirements.txt . -RUN pip install -r requirements.txt +RUN uv venv /opt/venv +# Use the virtual environment automatically +ENV VIRTUAL_ENV=/opt/venv +# Place entry points in the environment at the front of the path +ENV PATH="/opt/venv/bin:$PATH" +RUN uv pip install -r requirements.txt # copy project COPY . . \ No newline at end of file diff --git a/anatomy/models.py b/anatomy/models.py index 25f50297..37823c03 100644 --- a/anatomy/models.py +++ b/anatomy/models.py @@ -22,6 +22,7 @@ from collections import defaultdict from helpers.images import image_as_base64 import reversion +import urllib.parse image_storage = FileSystemStorage( # Physical file location ROOT @@ -540,6 +541,8 @@ class UserAnswer(UserAnswerBase): # s = self.answer.lower().strip() # s = s.translate(str.maketrans('', '', string.punctuation)) # return s + def get_answer_url_safe(self): + return urllib.parse.quote(self.answer_compare) def get_answer_string(self): return self.answer diff --git a/anatomy/templates/anatomy/mark.html b/anatomy/templates/anatomy/mark.html index 6e38c7bf..2641cbe4 100644 --- a/anatomy/templates/anatomy/mark.html +++ b/anatomy/templates/anatomy/mark.html @@ -38,22 +38,22 @@ {% for answer in user_answers %} {% if answer in answer_suggest_incorrect %} -
  • {{ answer }}
  • +
  • {{ answer }}
  • {% else %} -
  • {{ answer }}
  • +
  • {{ answer }}
  • {% endif %} {% endfor %} Marked:
    diff --git a/atlas/templates/atlas/case_display_block.html b/atlas/templates/atlas/case_display_block.html index 16be651b..249a1def 100755 --- a/atlas/templates/atlas/case_display_block.html +++ b/atlas/templates/atlas/case_display_block.html @@ -199,7 +199,13 @@

    Previous case: {{ case.previous_case.get_link }}

    -

    Next case: {{ case.next_case.get_link }}

    +

    Next case: + {% if case.next_case %} + {{ case.next_case.get_link }} + {% else %} + Clone and add next case + {% endif %} +

    {% include 'question_notes.html' %} diff --git a/atlas/urls.py b/atlas/urls.py index cc2ed4af..3663564b 100755 --- a/atlas/urls.py +++ b/atlas/urls.py @@ -306,6 +306,7 @@ urlpatterns = [ name="structure_update", ), path("structure/create", views.StructureCreate.as_view(), name="structure_create"), + path("series//thumbnail/fail", views.series_thumbnail_fail, name="series_thumbnail_fail"), path("series//thumbnail", views.series_thumbnail, name="series_thumbnail"), # TODO: case context series viewing (so that we can view series in the context of a case) path("series/", views.series_detail, name="series_detail"), @@ -372,6 +373,7 @@ urlpatterns = [ name="case_collection_form", ), path("case//clone", views.AtlasClone.as_view(), name="case_clone"), + path("case//clone/next", views.AtlasCloneNext.as_view(), name="case_clone_next"), # path("verified/", views.verified, name="verified"), # path("all_questions/", views.all_questions, name="all_questions"), path("case//scrap", views.atlas_scrap, name="case_scrap"), diff --git a/atlas/views.py b/atlas/views.py index 37579bfa..9ba8a1a1 100755 --- a/atlas/views.py +++ b/atlas/views.py @@ -197,13 +197,17 @@ def case_detail(request, pk): # logging.debug(atlas.subspecialty.first().name.all()) return render(request, "atlas/case_detail.html", {"case": case}) +@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, finding_pk=None): +def series_thumbnail(request, pk, fail_loudly=False): series = get_object_or_404(Series, pk=pk) - thumbnail, _ = series.get_thumbnail(recreate=True) + thumbnail, _ = series.get_thumbnail(recreate=True, fail_loudly=fail_loudly) return HttpResponse(thumbnail) @@ -1115,7 +1119,6 @@ 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""" @@ -1138,7 +1141,14 @@ class AtlasClone(AtlasCreateBase, AuthorOrCheckerRequiredMixin, CreateView): else: pass - initial_data = model_to_dict(old_object, exclude=["id"]) + 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"] return initial_data diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 140516a9..9add2c28 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: web: build: ./rad diff --git a/generic/models.py b/generic/models.py index fc326260..665773db 100644 --- a/generic/models.py +++ b/generic/models.py @@ -42,6 +42,8 @@ from django.contrib.auth.models import User from django.forms.models import model_to_dict from django.forms.utils import from_current_timezone, to_current_timezone +from loguru import logger + def findMiddle(input_list): """Returns the middle element of a list""" @@ -419,7 +421,7 @@ class SeriesBase(models.Model): else: return format_html('", "'.join(images)) - def get_thumbnail(self, recreate=False): + def get_thumbnail(self, recreate=False, fail_loudly=False): images = self.images.filter(removed=False) if len(images) < 1: @@ -431,7 +433,9 @@ class SeriesBase(models.Model): if recreate: thumbnailer.delete_thumbnails() thumbnail = thumbnailer["exam-list"] - except InvalidImageFormatError: + except InvalidImageFormatError as e: + if fail_loudly: + raise e return format_html( '', img ), len(images) diff --git a/generic/views.py b/generic/views.py index 71318134..c1fc4e28 100644 --- a/generic/views.py +++ b/generic/views.py @@ -33,8 +33,10 @@ from django.utils.decorators import method_decorator from django.core.cache import cache + import json import urllib +import urllib.parse from django.views import View from django.views.generic.edit import CreateView, UpdateView, DeleteView @@ -2652,6 +2654,7 @@ class GenericViewBase: @method_decorator(login_required) def question_user_answers_by_compare(self, request, pk, answer_compare): print(answer_compare) + answer_compare = urllib.parse.unquote(answer_compare) return self.question_user_answers(request, pk, answer_compare) @method_decorator(login_required) diff --git a/helpers/images.py b/helpers/images.py index f23f567c..236c1b06 100644 --- a/helpers/images.py +++ b/helpers/images.py @@ -62,7 +62,7 @@ def pil_dicom_image(source, exif_orientation=True, **options): #source = BytesIO(source.read()) # open file with pydicom - ds = pydicom.read_file(source) + ds = pydicom.dcmread(source) # return the image file return get_PIL_image(ds) diff --git a/requirements.txt b/requirements.txt index e3987902..4dfe748a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ #Django==3.2.13 -Django==5.0.2 +Django==5.1.4 django_debug_toolbar django_jquery django_reversion @@ -52,4 +52,5 @@ git+https://github.com/xkjq/django-jsonforms.git@bump-json-editor-lib django_svelte_jsoneditor psutil django-psutil-dash -django-template-partials \ No newline at end of file +django-template-partials +easy_thumbnails \ No newline at end of file