Compare commits

...
2 Commits
Author SHA1 Message Date
Ross 9c61068026 let people view open access series 2024-09-27 08:14:06 +01:00
Ross 24590ee2b1 fix crispy templates (finally...) 2024-09-27 08:13:57 +01:00
6 changed files with 83 additions and 68 deletions
+2 -1
View File
@@ -2,11 +2,12 @@ from django.core.exceptions import PermissionDenied
from .models import Case, CaseCollection, Series
def user_is_author_or_atlas_series_checker_or_atlas_marker(function):
def user_is_author_or_atlas_series_checker_or_atlas_marker_or_open_access(function):
def wrap(request, *args, **kwargs):
series = Series.objects.get(pk=kwargs["pk"])
if (
request.user in series.get_author_objects()
or series.open_access
or request.user.groups.filter(name="atlas_editor").exists()
or request.user.groups.filter(name="atlas_marker").exists()
or request.user.is_superuser
+3 -1
View File
@@ -4,7 +4,9 @@
{% block navigation%}
{{ block.super }}
{% include 'atlas/series_headers.html' %}
{% if can_edit %}
{% include 'atlas/series_headers.html' %}
{% endif %}
{% endblock %}
{% block content %}
+70 -62
View File
@@ -16,20 +16,24 @@
<div id="single-dicom-viewer" class="dicom-viewer" data-images="{{ image_url_array_and_count.0 }}" data-annotations=''>
</div>
{% if editing_finding < 1 %}
<button id="add-finding-button">Add finding</button>
{% endif %}
<button id="reset-viewport-button">Reset viewport</button>
<div id="finding-form">
<div class="hide" id="hidden-form">
<form method="post" id="series_finding_form">
{% csrf_token %}
{{series_finding_form|crispy}}
<input type="submit" value="Submit">
<button id="cancel-add-finding-button">Cancel</button>
</form>
{% if can_edit %}
{% if editing_finding < 1 %}
<button id="add-finding-button">Add finding</button>
{% endif %}
<button id="reset-viewport-button">Reset viewport</button>
<div id="finding-form">
<div class="hide" id="hidden-form">
<form method="post" id="series_finding_form">
{% csrf_token %}
{{series_finding_form|crispy}}
<input type="submit" value="Submit">
<button id="cancel-add-finding-button">Cancel</button>
</form>
</div>
</div>
</div>
{% else %}
<button id="reset-viewport-button">Reset viewport</button>
{% endif %}
<details open>
<summary>Findings</summary>
@@ -47,43 +51,46 @@
Structure(s): {% for s in finding.structures.all %}{{s.get_link}}{% endfor %}<br />
Condition(s): {% for s in finding.conditions.all %}{{s.get_link}}{% endfor %}<br />
Description: {{finding.description}}<br />
{% if request.user.is_superuser %}
<span _="on click toggle .hidden on next .extra-details">+</span>
<div class="hidden extra-details">
<h4>Annotation JSON</h4>
{% if request.user.is_superuser %}
<span _="on click toggle .hidden on next .extra-details">+</span>
<div class="hidden extra-details">
<h4>Annotation JSON</h4>
<pre>{{finding.annotation_json}}</pre>
<h4>Viewport JSON</h4>
<h4>Viewport JSON</h4>
<pre>{{finding.viewport_json}}</pre>
<h4>Image ID</h4>
<h4>Image ID</h4>
<pre>{{finding.current_image_id_index}}</pre>
</div>
{% endif %}
</div>
{% endif %}
</span>
<a href="{% url 'atlas:series_edit_finding' pk=series.pk finding_pk=finding.pk %}" class="edit-finding-link">Edit</a>
<a href="{% url 'atlas:delete_finding' pk=finding.pk %}" class="delete-finding-link">Delete</a>
{% if can_edit %}
<a href="{% url 'atlas:series_edit_finding' pk=series.pk finding_pk=finding.pk %}" class="edit-finding-link">Edit</a>
<a href="{% url 'atlas:delete_finding' pk=finding.pk %}" class="delete-finding-link">Delete</a>
{% endif %}
</div>
{% endfor %}
</details>
<details>
<summary>Truncate series</summary>
<p>
This will limit the series to the selected bounds (the rest of the images will be deleted). This is useful when you have a large volume of which only a small area is relevant to the case. NOTE: once deleted the images cannot be recovered on the site (they would have to be reuploaded if required). Make sure your images are shown in the correct order above and use test the test truncate button first.
</p>
Start <input id="lower-truncation-bound-input" type="number" value="1"> <button id="set-lower-truncation-bound-button">Set</button><br/>
End <input id="upper-truncation-bound-input"type="number" value="{{image_url_array_and_count.1}}"> <button id="set-upper-truncation-bound-button">Set</button><br/>
<button id="truncate-test-button">Test truncate</button>
<button id="truncate-button">Trucate series</button>
<div id="truncate-output"></div>
{% if can_edit %}
<details>
<summary>Truncate series</summary>
<p>
This will limit the series to the selected bounds (the rest of the images will be deleted). This is useful when you have a large volume of which only a small area is relevant to the case. NOTE: once deleted the images cannot be recovered on the site (they would have to be reuploaded if required). Make sure your images are shown in the correct order above and use test the test truncate button first.
</p>
Start <input id="lower-truncation-bound-input" type="number" value="1"> <button id="set-lower-truncation-bound-button">Set</button><br/>
End <input id="upper-truncation-bound-input"type="number" value="{{image_url_array_and_count.1}}"> <button id="set-upper-truncation-bound-button">Set</button><br/>
<button id="truncate-test-button">Test truncate</button>
<button id="truncate-button">Trucate series</button>
<div id="truncate-output"></div>
</details>
</details>
{% endif %}
{% endwith %}
<div>Author: {{ series.get_author_display }}</div>
{% if can_edit %}
<details>
<summary>Series info</summary>
<div>
@@ -105,25 +112,25 @@
Image details
</summary>
<form hx-post="{% url 'atlas:image_diff' %}"
hx-target="#temp"
hx-target="#temp"
>
{% for image in series.get_images %}
[{{ image.id }}] <a href='{% url "atlas:series_image_dicom" image.pk %}'>{{image.image.url}}</a>, pos: {{image.position}}, {{image.upload_filename}}
{% for image in series.get_images %}
[{{ image.id }}] <a href='{% url "atlas:series_image_dicom" image.pk %}'>{{image.image.url}}</a>, pos: {{image.position}}, {{image.upload_filename}}
{% if image.image %}
[{{image.get_file_size|filesizeformat}}]
{% endif %}
{% if image.image %}
[{{image.get_file_size|filesizeformat}}]
{% endif %}
{{image.image_md5_hash}} ({{image.is_dicom}}) {{image.image_blake3_hash}}
{{image.image_md5_hash}} ({{image.is_dicom}}) {{image.image_blake3_hash}}
<input type="checkbox" name="image-id" value="{{image.id}}">
<input type="checkbox" name="image-id" value="{{image.id}}">
<br />
<br />
{% comment %} {{image.get_dicom_info|safe}}<br /> {% endcomment %}
{% endfor %}
<button>Diff files</button>
{% endfor %}
<button>Diff files</button>
</form>
<span id="temp"></span>
</details>
@@ -131,21 +138,22 @@
<p>Total image size: {{series.get_total_image_size|filesizeformat}}</p>
<p><a href="{% url 'atlas:series_download' pk=series.pk %}">Download images</a></p>
</details>
<span id="diff-controls">show <span id="diff-show-all" _="on click
log '1'
for row in .diff.rows
show row
end">all</span> <span id="diff-show-diff" _="
on click
log 'go'
for row in <.diff tr/>
log row.children[0].innerHTML
if row.children[0].innerHTML is empty
hide row
end
end
">diff</span></span>
<span id="diff-controls">show <span id="diff-show-all" _="on click
log '1'
for row in .diff.rows
show row
end">all</span> <span id="diff-show-diff" _="
on click
log 'go'
for row in <.diff tr/>
log row.children[0].innerHTML
if row.children[0].innerHTML is empty
hide row
end
end
">diff</span></span>
{% endif %}
<script>
$(document).ready(function () {
+1
View File
@@ -297,6 +297,7 @@ urlpatterns = [
),
path("structure/create", views.StructureCreate.as_view(), name="structure_create"),
path("series/<int:pk>/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/<int:pk>", views.series_detail, name="series_detail"),
path("series/<int:pk>/authors", views.SeriesAuthorUpdate.as_view(), name="series_authors"),
path("series/", views.SeriesView.as_view(), name="series_view"),
+6 -3
View File
@@ -121,7 +121,7 @@ from autocomplete import HTMXAutoComplete
from .decorators import (
user_is_author_or_atlas_editor,
user_has_case_view_access,
user_is_author_or_atlas_series_checker_or_atlas_marker,
user_is_author_or_atlas_series_checker_or_atlas_marker_or_open_access,
user_is_atlas_editor,
user_is_author_or_atlas_series_checker,
user_is_atlas_marker,
@@ -198,7 +198,7 @@ def case_detail(request, pk):
@login_required
@user_is_author_or_atlas_series_checker_or_atlas_marker
@user_is_author_or_atlas_series_checker_or_atlas_marker_or_open_access
def series_thumbnail(request, pk, finding_pk=None):
series = get_object_or_404(Series, pk=pk)
@@ -208,10 +208,12 @@ def series_thumbnail(request, pk, finding_pk=None):
@login_required
@user_is_author_or_atlas_series_checker_or_atlas_marker
@user_is_author_or_atlas_series_checker_or_atlas_marker_or_open_access
def series_detail(request, pk, finding_pk=None):
series = get_object_or_404(Series, pk=pk)
can_edit = series.check_user_can_edit(request.user)
editing_finding = -1
if finding_pk is not None:
finding = get_object_or_404(SeriesFinding, pk=finding_pk)
@@ -228,6 +230,7 @@ def series_detail(request, pk, finding_pk=None):
"series": series,
"series_finding_form": series_finding_form,
"editing_finding": editing_finding,
"can_edit": can_edit,
},
)
+1 -1
View File
@@ -291,7 +291,7 @@ EMAIL_USE_SSL = True
ADMINS = [("Ross","ross@xkjq.uk")]
CRISPY_ALLOWED_TEMPLATE_PACK = 'bootstrap5'
CRISPY_ALLOWED_TEMPLATE_PACKS = ('bootstrap5',)
CRISPY_TEMPLATE_PACK = 'bootstrap5'
DEBUG_CONTAINER = False